2013-08-14 12 views
36

Sto lavorando a un'app che consente ai membri di effettuare un sondaggio (l'interlocutore ha una relazione uno a molti con la risposta). La risposta contiene member_id, question_id e la loro risposta.Associazione attiva di query di record di binari con "esiste"

Il sondaggio viene inviato tutto o niente, quindi se ci sono dei record nella tabella delle risposte per quel membro hanno completato il sondaggio.

La mia domanda è, come posso riscrivere la query qui sotto in modo che funzioni effettivamente? In SQL questo sarebbe un candidato principale per la parola chiave EXISTS.

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

risposta

82

È possibile utilizzare includes e quindi verificare se la relativa risposta (s) esiste in questo modo:

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

Ecco un'alternativa, con joins:

def surveys_completed 
    members.joins(:responses) 
end 

La soluzione utilizzando Rails 4:

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

domande simili:

+1

La prima opzione ha dato questo avviso di deprecazione http://pastebin.com/KbsNiqLy. Il secondo ha restituito gli stessi record 68 volte perché sono 68 domande, quindi l'ho modificato in questo modo: members.joins (: responses) .uniq.count – Lee

+2

L'avviso di ritiro non può essere evitato perché è necessario digitare una stringa per dice "NON È NULL" (non è possibile tradurre questo in puro ActiveRecord se non si utilizza Rails 4). Ne inserirò un terzo in un sec @lee – MrYoshiji

+0

Ho esaminato di più l'avviso di deprecazione e l'ho fatto: members.includes (: responses) .where ('responses.id IS NOT NULL'). References (: responses). conta e anche questo funziona. Quindi ora è una questione su quale sia il modo "migliore" – Lee

6

È possibile utilizzare SQL EXISTS parola chiave in eleganti Rails-ish modo utilizzando Where Exists gemma:

members.where_exists(:responses).count 

Naturalmente è possibile utilizzare SQL grezzo così:

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

L'altra risposta non genererà SQL che utilizza il Parola chiave ESISTA. In questo modo sarà molto più performante! – rept

1

È possibile anche utilizzare un subquery:

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

In confronto a qualcosa con includes non caricherà i modelli associati (che è un vantaggio in termini di prestazioni se non ne hai bisogno).

Problemi correlati