Frage

Nur diese zu aktualisieren, da es eine Menge Leute scheint kommen, wenn Sie mit Rails 4 Blick auf den Antworten von Trung Lê` und VinniVidiVicci.

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

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

Ich hoffe es eine einfache Lösung, die nicht find_by_sql mit sich bringt, wenn nicht, dann denke ich, dass zur Arbeit hat.

Ich habe diesen Artikel , die diese verweist:

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

, das ist die gleiche wie

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

Ich frage mich, ob es einen Weg gibt NOT IN damit zu tun, wie:

SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)
War es hilfreich?

Lösung

Ich verwende diese:

Topic.where('id NOT IN (?)', Array.wrap(actions))

Wo actions ist ein Array mit: [1,2,3,4,5]

Edit:

Für Rails 4 Notation:

Article.where.not(title: ['Rails 3', 'Rails 5']) 

Andere Tipps

FYI, in Schienen 4 können Sie not Syntax verwenden:

Article.where.not(title: ['Rails 3', 'Rails 5'])

Sie können so etwas wie versuchen:

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

Sie müssen möglicherweise @forums.map(&:id).join(',') tun. Ich kann mich nicht daran erinnern, ob Rails wird das Argument in eine CSV-Liste, wenn es abzählbar ist.

Sie können auch dies tun:

# 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)

Mit Arel:

topics=Topic.arel_table
Topic.where(topics[:forum_id].not_in(@forum_ids))

oder, falls bevorzugt:

topics=Topic.arel_table
Topic.where(topics[:forum_id].in(@forum_ids).not)

und da Schienen 4 auf:

topics=Topic.arel_table
Topic.where.not(topics[:forum_id].in(@forum_ids))

Bitte beachten, schließlich wollen Sie nicht die forum_ids die ids Liste sein, sondern eine Unterabfrage, wenn ja, dann sollten Sie etwas tun, bevor die Themen bekommen:

@forum_ids = Forum.where(/*whatever conditions are desirable*/).select(:id)

auf diese Weise Sie alles in einer einzigen Abfrage erhalten: so etwas wie:

select * from topic 
where forum_id in (select id 
                   from forum 
                   where /*whatever conditions are desirable*/)

Beachten Sie auch, dass schließlich Sie nicht wollen, dies zu tun, sondern vielmehr eine Join -. Was effizienter sein könnte

erweitern, um auf @Trung Lê Antwort, in Rails 4 können Sie die folgenden Aktionen ausführen:

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

Und man könnte es noch einen Schritt weiter. Wenn Sie nur die veröffentlichten Themen ersten Filter benötigen und und Filter aus Iden Sie nicht wollen, könnten Sie dies tun:

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

Schienen 4 macht es so viel einfacher!

Die akzeptierte Lösung schlägt fehl, wenn @forums leer. Um diese ich umgehen musste tun

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

Oder, wenn mit Rails 3 +:

Topic.where( 'forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id)) ).all

Die meisten Antworten oben sollten Sie genügen aber wenn Sie viel mehr solcher Prädikat und komplexe Kombinationen überprüfen squeel . Sie werden sich wie zu etwas tun können:

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)}

Sie können einen Blick auf die meta_where Plugin von Ernie Miller haben wollen. Ihre SQL-Anweisung:

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

... könnte wie folgt ausgedrückt werden:

Topic.where(:forum_id.nin => @forum_ids)

Ryan Bates von Railscasts erstellt einen schönen Screencasts MetaWhere zu erklären.

Nicht sicher, ob dies ist, was Sie suchen, aber in meinen Augen sieht es auf jeden Fall besser als eine eingebettete SQL-Abfrage.

Die ursprüngliche Post erwähnt speziell numerisches IDs verwenden, aber ich kam hier für die Syntax suche einen NOT IN mit einer Reihe von Strings zu tun.

Active wird, dass man einfach nur schön zu:

Thing.where(['state NOT IN (?)', %w{state1 state2}])

Kann man diese Forum-IDs auf pragmatische Weise ausgearbeitet werden? z.B. Sie können diese Foren irgendwie finden - wenn das der Fall ist, sollten Sie so etwas wie

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

Welche effizienter wäre als ein tun SQL not in

Auf diese Weise optimiert, um die Lesbarkeit, aber es ist nicht so effizient in Bezug auf den Datenbankabfragen:

# Retrieve all topics, then use array subtraction to
# find the ones not in our list
Topic.all - @forums.map(&:id)

Sie können SQL in Ihren Bedingungen verwenden:

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

Huckepack off von jonnii:

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

mit zupfen, anstatt Mapping über die Elemente

gefunden über RailsConf 2012 10 Dinge, die Sie nicht wissen, Schienen tun konnte

Wenn Sie Abfrage ein leeres Array add „<< 0“ auf das Feld in dem where-Block, damit es nicht zurückgeben „NULL“ und brechen Sie die Abfrage aus.

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

Wenn Aktionen könnten eine leere oder leere Array sein.

Hier ist ein komplexer „nicht in“ Abfrage eine Unterabfrage in Schienen 4 mit squeel verwenden. Natürlich sehr langsam in dem entsprechenden SQL-Vergleich, aber hey, es funktioniert.

    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)}
    }

Die ersten zwei Methoden im Rahmen gibt andere Bereiche, die die Aliase cavtl1 und tl1 erklären. << ist nicht in Bediener in squeel.

Hope dies hilft jemand.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top