2010-11-17 9 views
16

Piszę zapytanie Rails 3 ActiveRecord, używając składni "where", która używa zarówno SQL IN, jak i operatora SQL OR i nie może dowiedzieć się, jak używaj ich obu razem.Rails 3 Zapytanie ActiveRecord przy użyciu zarówno SQL IN, jak i operatorów SQL OR

Prace Ten kod (w moim modelu użytkownika):

Question.where(:user_id => self.friends.ids) 
#note: self.friends.ids returns an array of integers 

ale ten kod

Question.where(:user_id => self.friends.ids OR :target => self.friends.usernames) 

zwraca ten błąd

syntax error, unexpected tCONSTANT, expecting ')' 
...user_id => self.friends.ids OR :target => self.friends.usern... 

Każdy pomysł, jak napisać to w szynach lub po prostu jakie powinno być surowe zapytanie SQL?

Odpowiedz

-7

surowego SQL

SELECT * 
FROM table 
WHERE user_id in (LIST OF friend.ids) OR target in (LIST OF friends.usernames) 

z każdej listy przecinkiem osobnym. Nie znam dobrze rzeczy Rails ActiveRecord. Na I byłoby po prostu postawić przecinek między tymi dwoma warunkami, ale idk o OR

+0

Dzięki! Dokładne zapytanie, którego użyłem to: Question.where ('target IN (?) LUB user_id IN (?)', Self.friends.usernames, self.friends.ids) – kateray

+0

Dobrze, zapomniałem o tym. Czuję, że powinny być sposobem w formacie => hash. nie powinieneś potrzebować wzorca, aby dodać OR pomiędzy 2 ważnymi warunkami, ale kogo to obchodzi. –

+13

ideą aktywnego rekordu jest być agnostykiem bazy danych, więc używanie surowego sql w szynach nie powinno być uważane za najlepsze rozwiązanie, z wyjątkiem sytuacji, gdy wydajność ulega pogorszeniu, co nie ma miejsca w tym zapytaniu. – nunopolonia

45

Nie trzeba używać surowego SQL, wystarczy podać wzór jako ciąg znaków, a następnie dodaj nazwanych parametrów:

Question.where('user_id in (:ids) or target in (:usernames)', 
       :ids => self.friends.ids, :usernames => self.friends.usernames) 

Albo parametry pozycyjne:

Question.where('user_id in (?) or target in (?)', 
       self.friends.ids, self.friends.usernames) 

można również skorzystać z doskonałą Squeel gem, jak @erroric wskazał na jego odpowiedź (blok my { } jest potrzebne tylko wtedy, gdy potrzebny jest dostęp do self lub zmienne instancji):

Question.where { user_id.in(my { self.friends.ids }) | 
       target.in(my { self.friends.usernames }) } 
+0

Hej człowieku potrzebujesz pomocy ... Jak napisać zapytanie, czy muszę wybrać wszystkie wiadomości między dwoma użytkownikami (powiedzmy id1 i id2) i wiadomościami sender_id i receiver_id. Dlatego muszę wybrać "wszystkie wiadomości, których ((sender_id = id1 i reciver_id = id2) lub (sender_id = id2 i reciver_id = id1))". Muszę je posortować i paginować, co nie da się zrobić, jeśli zrobię dwa oddzielne zapytanie, a następnie dodaję (będę miał pożądany wynik, ale stronicowanie stanie się trudne). Więc proszę, pomóżcie mi w napisaniu zapytania o jedną linię dla tego. Każda pomoc zostanie doceniona. – zeal

+0

@zeal, proszę otworzyć nowe pytanie, opisując to, co już wypróbowałeś i jak możemy pomóc. Społeczność jest świetna, ale musisz nauczyć się jej używać. –

9

Choć Rails 3 AR nie daje lub operator nadal można osiągnąć ten sam rezultat, bez przechodzenia przez całą drogę w dół do SQL i używają Arel bezpośrednio. Rozumiem przez to, że można zrobić to tak:

t = Question.arel_table 
Question.where(t[:user_id].in(self.friends.ids).or(t[:username].in(self.friends.usernames))) 

Niektórzy mogą powiedzieć, że nie jest tak ładna, niektórzy mogą powiedzieć, że to całkiem po prostu dlatego, że nie zawiera SQL. Tak czy inaczej to na pewno mogłaby być ładniejsza i tam gem dla niej zbyt: MetaWhere

Więcej informacji można znaleźć ten railscast: http://railscasts.com/episodes/215-advanced-queries-in-rails-3 i strona MetaWhere: http://metautonomo.us/projects/metawhere/

UPDATE: Później Ryan Bates dokonał inny railscast o metawhere i metasearch: http://railscasts.com/episodes/251-metawhere-metasearch Później jednak Metawhere (i wyszukiwanie) stały się mniej lub bardziej legendarnymi klejnotami. To znaczy. nawet nie działają z Rails 3.1. Autor uznał, że (Metawhere i wyszukiwanie) potrzebowali drastycznego przepisania. Tak bardzo, że poszedł razem po nowy klejnot. Następcą Metawhere jest Squeel. Czytaj więcej o autorach zapowiedzi tutaj: http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/ i sprawdzić na stronie domowej projektu: http://erniemiller.org/projects/squeel/ „Metasearch 2.0” nazywa plądrować i można przeczytać coś o tym tutaj: http://erniemiller.org/2011/04/01/ransack-the-library-formerly-known-as-metasearch-2-0/

6

Alternatywnie, można użyć Squeel. Dla moich oczu jest to prostsze.Można to osiągnąć zarówno IN (>>) i OR (|) operacji przy użyciu następującej składni:

Question.where{(:user_id >> my{friends.id}) | (:target >> my{friends.usernames})} 

I ogólnie owinąć moje warunki (...) aby zapewnić odpowiednią kolejność operacji - zarówno INS zdarzyć przed OR.

Blok my{...} wykonuje metody z kontekstu self zdefiniowanego przed wywołaniem Squeela - w tym przypadku Question. Wewnątrz bloku Squeel, self odnosi się do obiektu Squeel, a nie obiektu Question(). Można obejść to, używając opakowania my{...}, aby przywrócić pierwotny kontekst.

+1

Wygląda dobrze, ale [wypięli "rekord" z Active Record] (https://github.com/ernie/squeel#compatibility-with-active-record), co wydaje się niefortunne. – crizCraig

Powiązane problemy