Jak wyrazić zapytanie Nie w ActiveRecord/Rails?
Aby to zaktualizować, ponieważ wydaje się, że wiele osób do tego dochodzi, jeśli używasz Rails 4, spójrz na odpowiedzi Trung Lê ' i VinniVidiVicci.
Topic.where.not(forum_id:@forums.map(&:id))
Topic.where(published:true).where.not(forum_id:@forums.map(&:id))
Mam nadzieję, że istnieje łatwe rozwiązanie, które nie obejmuje find_by_sql
, Jeśli nie, to chyba będzie musiało zadziałać.
Znalazłem Ten artykuł który odwołuje się do tego:
Topic.find(:all, :conditions => { :forum_id => @forums.map(&:id) })
Czyli to samo co
SELECT * FROM topics WHERE forum_id IN (<@forum ids>)
Zastanawiam się, czy jest jakiś sposób, aby zrobić NOT IN
z tym, jak:
SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)
15 answers
Używam tego:
Topic.where('id NOT IN (?)', Array.wrap(actions))
Gdzie actions
jest tablicą z: [1,2,3,4,5]
Edit:
Dla notacji Rails 4:
Article.where.not(title: ['Rails 3', 'Rails 5'])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-28 22:43:24
FYI, w Rails 4 możesz użyć składni not
:
Article.where.not(title: ['Rails 3', 'Rails 5'])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 00:21:38
Możesz spróbować czegoś takiego:
Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.map(&:id)])
Być może będziesz musiał to zrobić @forums.map(&:id).join(',')
. Nie pamiętam, czy Rails zamieni argument na listę CSV, jeśli można go wyliczyć.
# in topic.rb
named_scope :not_in_forums, lambda { |forums| { :conditions => ['forum_id not in (?)', forums.select(&:id).join(',')] }
# in your controller
Topic.not_in_forums(@forums)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 01:04:52
Używając Arel:
topics=Topic.arel_table
Topic.where(topics[:forum_id].not_in(@forum_ids))
Lub, jeśli preferowane:
topics=Topic.arel_table
Topic.where(topics[:forum_id].in(@forum_ids).not)
I od rails 4 na:
topics=Topic.arel_table
Topic.where.not(topics[:forum_id].in(@forum_ids))
Zauważ, że w końcu nie chcesz, aby forum_ids było listą ids, ale raczej zapytaniem podrzędnym, jeśli tak, to powinieneś zrobić coś takiego przed uzyskaniem tematów:
@forum_ids = Forum.where(/*whatever conditions are desirable*/).select(:id)
W ten sposób otrzymujesz wszystko w jednym zapytaniu: coś w stylu:
select * from topic
where forum_id in (select id
from forum
where /*whatever conditions are desirable*/)
Zauważ również, że w końcu nie chcesz tego robić, ale raczej dołączyć - co może być więcej wydajny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-27 16:05:23
Aby rozwinąć @Trung Lê answer, w Rails 4 możesz wykonać następujące czynności:
Topic.where.not(forum_id:@forums.map(&:id))
I mógłbyś pójść o krok dalej.
Jeśli najpierw musisz filtrować tylko opublikowane tematy i , a następnie odfiltrować identyfikatory, których nie chcesz, możesz to zrobić:
Topic.where(published:true).where.not(forum_id:@forums.map(&:id))
Rails 4 sprawia, że jest to o wiele łatwiejsze!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 16:08:29
Przyjęte rozwiązanie nie powiedzie się, jeśli @forums
jest puste. Aby obejść to, musiałem to zrobić
Topic.find(:all, :conditions => ['forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id))])
Lub, jeśli używasz Rails 3+:
Topic.where( 'forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id)) ).all
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 01:01:30
Większość powyższych odpowiedzi powinna Ci wystarczyć, ale jeśli robisz dużo więcej takich predykatów i złożonych kombinacji sprawdź Squeel . Będziesz mógł zrobić coś takiego:
Topic.where{{forum_id.not_in => @forums.map(&:id)}}
Topic.where{forum_id.not_in @forums.map(&:id)}
Topic.where{forum_id << @forums.map(&:id)}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 00:59:48
Możesz rzucić okiem na wtyczkę meta_where autorstwa Erniego Millera. Twoje polecenie SQL:
SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)
...można wyrazić tak:
Topic.where(:forum_id.nin => @forum_ids)
Ryan Bates z Railscasts stworzyłładny screencast wyjaśniający MetaWhere .
Nie jestem pewien, czy to jest to, czego szukasz, ale moim oczom na pewno wygląda lepiej niż osadzone zapytanie SQL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 01:02:11
Czy te identyfikatory forum można wypracować w sposób pragmatyczny? np. czy można jakoś znaleźć te fora-jeśli tak to należy zrobić coś w stylu
Topic.all(:joins => "left join forums on (forums.id = topics.forum_id and some_condition)", :conditions => "forums.id is null")
Który byłby bardziej efektywny niż robienie SQL not in
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-29 20:24:18
Ten sposób optymalizuje czytelność, ale nie jest tak skuteczny pod względem zapytań do bazy danych:
# Retrieve all topics, then use array subtraction to
# find the ones not in our list
Topic.all - @forums.map(&:id)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-28 07:31:20
Oryginalny post wyraźnie wspomina o używaniu identyfikatorów numerycznych, ale przyszedłem tutaj szukając składni do robienia NOT in z tablicą łańcuchów.
ActiveRecord też sobie z tym poradzi:
Thing.where(['state NOT IN (?)', %w{state1 state2}])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 11:42:41
Możesz używać sql w swoich warunkach:
Topic.find(:all, :conditions => [ "forum_id NOT IN (?)", @forums.map(&:id)])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-29 19:58:26
Piggybacking off of jonnii:
Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.pluck(:id)])
Używanie plucka zamiast mapowania elementów
Znaleziono przez railsconf 2012 10 rzeczy, o których nie wiedziałeś, że rails może zrobić
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 17:15:15
Gdy odpytywasz pustą tablicę, dodaj "
Topic.where('id not in (?)',actions << 0)
Jeśli akcje mogą być pustą lub pustą tablicą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-18 18:33:31
Tutaj jest bardziej złożone zapytanie "Nie w", używając subquery w rails 4 używając squeela. Oczywiście bardzo wolno w porównaniu do równoważnego sql, ale hej, to działa.
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)}
}
Pierwsze 2 metody w zakresie to inne zakresy deklarujące aliasy cavtl1 i tl1. Mam nadzieję, że to komuś pomoże.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-10 04:09:42