Как выразить запрос NOT IN с ActiveRecord / Rails? - PullRequest
191 голосов
/ 29 ноября 2010

Просто чтобы обновить это, так как кажется, что многие приходят к этому, если вы используете Rails 4, посмотрите ответы Трунга Лэ и Виннивидичи.

Topic.where.not(forum_id:@forums.map(&:id))

Topic.where(published:true).where.not(forum_id:@forums.map(&:id))

Я надеюсь, что есть простое решение, которое не включает find_by_sql, если нет, то, думаю, это сработает.

Я нашел эту статью , которая ссылается на это:

Topic.find(:all, :conditions => { :forum_id => @forums.map(&:id) })

, что совпадает с

SELECT * FROM topics WHERE forum_id IN (<@forum ids>)

Мне интересно, есть ли способ сделать NOT IN, например:

SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)

Ответы [ 15 ]

1 голос
/ 29 ноября 2010

Могут ли эти идентификаторы форума быть выработаны прагматично? например можете ли вы найти эти форумы как-нибудь - если это так, вы должны сделать что-то вроде

Topic.all(:joins => "left join forums on (forums.id = topics.forum_id and some_condition)", :conditions => "forums.id is null")

Что было бы более эффективно, чем выполнение SQL not in

0 голосов
/ 10 августа 2015

Вот более сложный запрос «не в», использующий подзапрос в рельсах 4 с использованием squeel. Конечно, очень медленно по сравнению с эквивалентным SQL, но эй, это работает.

    scope :translations_not_in_english, ->(calmapp_version_id, language_iso_code){
      join_to_cavs_tls_arr(calmapp_version_id).
      joins_to_tl_arr.
      where{ tl1.iso_code == 'en' }.
      where{ cavtl1.calmapp_version_id == my{calmapp_version_id}}.
      where{ dot_key_code << (Translation.
        join_to_cavs_tls_arr(calmapp_version_id).
        joins_to_tl_arr.    
        where{ tl1.iso_code == my{language_iso_code} }.
        select{ "dot_key_code" }.all)}
    }

Первые 2 метода в области видимости - это другие области, которые объявляют псевдонимы cavtl1 и tl1. << - оператор not in в squeel. </p>

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 29 ноября 2013

Когда вы запрашиваете пустой массив, добавьте «<< 0» в массив в блоке where, чтобы он не возвращал «NULL» и не прерывал запрос. </p>

Topic.where('id not in (?)',actions << 0)

Если действия могут быть пустым или пустым массивом.

0 голосов
/ 15 октября 2012

Спекуляция от Джонни:

Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.pluck(:id)])

с использованием pluck вместо отображения элементов

найдено через railsconf 2012 10 вещей, о которых вы не знали, что rails может сделать

0 голосов
/ 29 ноября 2010

Вы можете использовать sql в ваших условиях:

Topic.find(:all, :conditions => [ "forum_id NOT IN (?)", @forums.map(&:id)])
...