2013-08-14 12 views
36

Pracuję nad aplikacją, która umożliwia członkom wzięcie udziału w ankiecie (członek ma jeden do wielu relacji z odpowiedzią). Odpowiedź zawiera identyfikator member_id, question_id i ich odpowiedź.Szyny aktywne skojarzenie rekordów rekordów z "istniejącymi"

Ankieta została przesłana całkowicie lub w całości, więc jeśli w tabeli Odpowiedzi dla tego uczestnika są jakieś zapisy, wypełnili ankietę.

Moje pytanie brzmi, w jaki sposób mogę ponownie zapisać poniższe zapytanie, aby działało? W SQL byłby to najlepszy kandydat na słowo kluczowe EXISTS.

def surveys_completed 
    members.where(responses: !nil).count 
end 

Odpowiedz

82

można wykorzystywać includes a następnie sprawdzenie, czy związane z reakcji (i) występuje w następujący sposób:

def surveys_completed 
    members.includes(:responses).where('responses.id IS NOT NULL') 
end 

tutaj stanowi alternatywę z joins:

def surveys_completed 
    members.joins(:responses) 
end 

Roztwór za pomocą Rails 4:

def surveys_completed 
    members.includes(:responses).where.not(responses: { id: nil }) 
end 

Podobne pytania:

+1

Pierwsza opcja zawierała informację o tym wycofaniu http://pastebin.com/KbsNiqLy. Drugi zwrócił te same rekordy 68 razy, ponieważ ich 68 pytań zostało zmienionych w następujący sposób: members.joins (: odpowiedzi) .uniq.count – Lee

+2

Nie można uniknąć powiadomienia o wycofaniu, ponieważ musimy wpisać ciąg znaków, aby mówi "IS NOT NULL" (nie można tego przetłumaczyć w czystym ActiveRecord, chyba że używasz Rails 4). Wstawię trzecią możliwość w sekundę @lee – MrYoshiji

+0

Spojrzałem bardziej na ogłoszenie o odstąpieniu i zrobiłem to: members.includes (: odpowiedzi) .where ("responses.id NIE JEST NULL"). References (: odpowiedzi). liczyć i to też działa. Więc teraz jest pytanie, w którą stronę jest "najlepsza" droga. – Lee

6

Można użyć SQL EXISTS słowa kluczowego w eleganckich Rails-owski sposób stosując Where Exists GEM:

members.where_exists(:responses).count 

Oczywiście można użyć surowego SQL, a także:

members.where("EXISTS" \ 
    "(SELECT 1 FROM responses WHERE responses.member_id = members.id)"). 
    count 
+1

Druga odpowiedź nie generuje SQL, który używa Słowo kluczowe EXIST. W ten sposób będzie znacznie bardziej wydajne! – rept

1

Można również użyć podzapytanie:

members.where(id: Response.select(:member_id)) 

W porównaniu do czegoś z includes nie załaduje powiązanych modeli (co jest korzyścią z wydajności, jeśli ich nie potrzebujesz).

Powiązane problemy