Po prostu zaktualizuj to, ponieważ wydaje się, że wiele osób przychodzi do tego, 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 proste rozwiązanie, które nie wymaga 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) })
który jest taki sam jak
SELECT * FROM topics WHERE forum_id IN (<@forum ids>)
Zastanawiam się, czy istnieje sposób, aby to zrobić NOT IN
, na przykład:
SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)
ruby-on-rails
rails-activerecord
Toby Joiner
źródło
źródło
Person.all(:name.not => ['bob','rick','steve'])
Odpowiedzi:
Szyny 4+:
Szyny 3:
Gdzie
actions
jest tablica z:[1,2,3,4,5]
źródło
Topic.where('id NOT IN (?)', (actions.empty? ? '', actions)
. Nadal by się zepsuł na zero, ale uważam, że tablica, którą przekazujesz, jest zwykle generowana przez filtr, który zwróci[]
co najmniej, a nigdy zero. Polecam sprawdzenie Squeel, DSL na Active Record. Następnie możesz zrobićTopic.where{id.not_in actions}
:, zero / puste / lub w inny sposób..empty?
na.blank?
i jesteś zero-proofDo Twojej wiadomości, w Rails 4 możesz użyć
not
składni:źródło
Możesz spróbować czegoś takiego:
Być może będziesz musiał zrobić
@forums.map(&:id).join(',')
. Nie pamiętam, czy Railsy umieszczą argument na liście CSV, jeśli jest ona wyliczalna.Możesz także to zrobić:
źródło
Korzystanie z Arel:
lub, jeśli preferowane:
i od szyn 4 na:
Zauważ, że ostatecznie nie chcesz, aby forum_ids była listą identyfikatorów, a raczej podzapytaniem, jeśli tak, to powinieneś zrobić coś takiego przed uzyskaniem tematów:
w ten sposób otrzymujesz wszystko w jednym zapytaniu: coś takiego:
Zauważ też, że ostatecznie nie chcesz tego robić, a raczej dołączyć - co może być bardziej wydajne.
źródło
EXPLAIN
!Aby rozwinąć odpowiedź @Trung Lê, w Rails 4 możesz wykonać następujące czynności:
I możesz pójść o krok dalej. Jeśli musisz najpierw odfiltrować tylko opublikowane tematy, a następnie odfiltrować niepotrzebne identyfikatory, możesz to zrobić:
Rails 4 sprawia, że jest to o wiele łatwiejsze!
źródło
Akceptowane rozwiązanie kończy się niepowodzeniem, jeśli
@forums
jest puste. Aby to obejść, musiałem to zrobićLub, jeśli używasz Rails 3+:
źródło
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:
źródło
Możesz zajrzeć do wtyczki meta_where autorstwa Ernie Millera. Twoja instrukcja SQL:
... można wyrazić w następujący sposób:
Ryan Bates of Railscasts stworzył fajny screencast wyjaśniający MetaWhere .
Nie jestem pewien, czy tego właśnie szukasz, ale moim zdaniem z pewnością wygląda to lepiej niż wbudowane zapytanie SQL.
źródło
Oryginalny post wspomina konkretnie o numerycznych identyfikatorach, ale przyszedłem tutaj, szukając składni do wykonywania NOT IN z tablicą ciągów.
ActiveRecord poradzi sobie również z tym dobrze:
źródło
Czy te identyfikatory forum można opracować w sposób pragmatyczny? np. czy możesz jakoś znaleźć te fora - w takim przypadku powinieneś zrobić coś takiego
Co byłoby bardziej wydajne niż wykonywanie SQL
not in
źródło
W ten sposób optymalizuje się pod kątem czytelności, ale nie jest tak wydajna pod względem zapytań do bazy danych:
źródło
Możesz używać sql w swoich warunkach:
źródło
Piggybacking z jonnii:
za pomocą skubania zamiast mapowania elementów
znalezione przez railsconf 2012 10 rzeczy, o których nie wiedziałeś, że mogą zrobić szyny
źródło
Kiedy przeszukujesz pustą tablicę, dodaj „<< 0” do tablicy w bloku where, aby nie zwracała „NULL” i nie przerywała zapytania.
Jeśli akcje mogą być pustą lub pustą tablicą.
źródło
Topic.where("id NOT IN (?)", actions.presence || [0])
Oto bardziej złożone zapytanie „nie w”, wykorzystujące podzapytanie w szynach 4 za pomocą squeel. Oczywiście bardzo wolno w porównaniu do równoważnej sql, ale hej, to działa.
Pierwsze 2 metody w zakresie to inne zakresy, które deklarują aliasy cavtl1 i tl1. << to operator in in squeel.
Mam nadzieję, że to komuś pomoże.
źródło