2010-09-21 2 views
4

В рельсах у меня есть 2 таблицы:Как выбрать записи, в которых ребенок не существует

bans(ban_id, admin_id) 
ban_reasons(ban_reason_id, ban_id, reason_id) 

Я хочу найти все bans для определенного администратора, где нет ни одной записи в таблице ban_reasons. Как я могу сделать это в Rails, не зацикливая все записи запрета и отфильтровывая все из них с помощью ban.ban_reasons.nil?. Я хочу сделать это (надеюсь) с использованием одного оператора SQL.

мне просто нужно делать: (Но я хочу, чтобы сделать это «рельсы» путь)

SELECT bans.* FROM bans WHERE admin_id=1234 AND 
           ban_id NOT IN (SELECT ban_id FROM ban_reasons) 

ответ

2

Ваше решение отлично работает (только один запрос), но это почти обычный SQL:

bans = Ban.where("bans.id NOT IN (SELECT ban_id from ban_reason)") 

Вы также можете попробовать следующее, и пусть рельсы делают часть работы:

bans = Ban.where("bans.id NOT IN (?)", BanReason.select(:ban_id).map(&:ban_id).uniq) 
+0

Есть ли разница в производительности между двумя? Получает ли второй результат больше запросов? –

+0

Да, вы получите еще один запрос со вторым ... Я думаю, что проблема с производительностью действительно зависит от вашего размера БД. – Yannis

+0

Я предполагаю, что если целью является использование Rails независимо от стоимости, то предложение работает, но производительность будет ужасно страдать для больших наборов данных. –

2

ActiveRecord только получает вас к точке, все после того, как должно быть сделано сырым SQL. Хорошая вещь о AR заключается в том, что это довольно легко сделать.

Однако, поскольку Rails 3 вы можете использовать почти все с API AREL, хотя исходный SQL может выглядеть или не выглядеть более читаемым.

Я бы с сырой SQL и вот еще один запрос, вы можете попробовать, если у вас не работают хорошо:

SELECT  b.* 
FROM   bans b 
LEFT JOIN ban_reason br on b.ban_id = br.ban_id 
WHERE  br.ban_reason_id IS NULL 
+0

Это будет лучше работать с большинством db, чем с другим выше. Многие db имеют довольно низкую производительность IN (где они определяют множество). Это будет иметь определенный успех, а также поиск нулевого значения в соединении, но я все же думаю, что это, вероятно, лучше, чем выше. – Scott

+0

Реализация этого как НЕ EXISTS() была бы более естественным синтаксисом для этого запроса, я думаю, но я думаю, что вы правы, что SQL - это путь. –

0

Usi ng Where Exists драгоценный камень (который я автор):

Ban.where(admin_id: 123).where_not_exists(:ban_reasons) 
Смежные вопросы