2013-07-30 14 views
5

Sto cercando di capire come creare una query per filtrare alcuni risultati basati su un join interno.come impedire i duplicati con la query di inner join (Postgres)

Considerate i seguenti dati:

formulation_batch 
----- 
id project_id name  
1 1   F1.1 
2 1   F1.2 
3 1   F1.3 
4 1   F1.all 

formulation_batch_component 
----- 
id formulation_batch_id component_id 
1 1      1 
2 2      2 
3 3      3 
4 4      1 
5 4      2 
6 4      3 
7 4      4 

Vorrei selezionare tutti i record con un formulation_batch project_id di 1, ed ha un formulation_batch_component con una component_id di 1 o 2. Quindi eseguire la seguente query:

SELECT "formulation_batch".* 
FROM "formulation_batch" 
INNER JOIN "formulation_batch_component" 
ON "formulation_batch"."id" = "formulation_batch_component"."formulationBatch_id" 
WHERE "formulation_batch"."project_id" = 1 
    AND (("formulation_batch_component"."component_id" = 2 
     OR "formulation_batch_component"."component_id" = 1)) 

Tuttavia, questo restituisce una voce duplicata:

1;"F1.1" 
2;"F1.2" 
4;"F1.all" 
4;"F1.all" 

Esiste un modo per modificare questa query in modo tale da ottenere solo i record unici di formulazione_batch che corrispondono ai criteri?

EG:

1;"F1.1" 
2;"F1.2" 
4;"F1.all" 

Grazie per il vostro tempo!

risposta

7

Un modo potrebbe essere quello di utilizzare distinct:

SELECT distinct "formulation_batch".* 
FROM "formulation_batch" 
INNER JOIN "formulation_batch_component" 
ON "formulation_batch"."id" = "formulation_batch_component"."formulationBatch_id" 
WHERE "formulation_batch"."project_id" = 1 
    AND (("formulation_batch_component"."component_id" = 2 
     OR "formulation_batch_component"."component_id" = 1)) 
+0

Grazie, ho dimenticato distinto. Non è il massimo delle prestazioni, ma è ancora meglio che filtrarlo a livello di software. – drkstr1

10

In questo caso è possibile applicare il distinct prima della join forse rendendo più performante:

select fb.* 
from 
    formulation_batch fb 
    inner join 
    (
     select distinct formulationbatch_id 
     from formulation_batch_component 
     where component_id in (1, 2) 
    ) fbc on fb.id = fbc.formulationbatch_id 
where fb.project_id = 1 

Avviso come utilizzare alias per i nomi delle tabelle per rendere più chiara la query. Inoltre, l'operatore in è molto utile. L'uso di virgolette doppie con tali identificatori non è necessario.

+0

Grazie per l'idea sull'ottimizzazione. La query viene effettivamente generata da un ORM, ma penso di avere un modo per implementarlo in questo modo (più o meno allo stesso modo in cui l'ho modificato per selezionare distinti nella query esterna). – drkstr1

+0

Nel mio test, innerjoining come sopra è stato anche più veloce rispetto all'utilizzo dei formulationbatch_ids in una clausola WHERE, vale a dire:. 'selezionare fb * da formulation_batch fb dove fb.project_id = 1, fb.id IN ( selezionare formulationbatch_id da formulation_batch_component dove component_id in (1, 2) ) ' –

2

So che la domanda chiede come evitare i duplicati con inner join ma potrebbe utilizzare una clausola IN nel predicato.

SELECT "formulation_batch".* 
FROM "formulation_batch" fb 
ON "formulation_batch"."id" = "formulation_batch_component"."formulationBatch_id" 
WHERE "formulation_batch"."project_id" = 1 
AND fb.id IN (SELECT "formulation_batch"."id" 
       FROM formulation_batch_component 
       WHERE (("formulation_batch_component"."component_id" = 2 
         OR "formulation_batch_component"."component_id" = 1)) 
+0

Questa è la soluzione migliore per la domanda che stavo cercando di chiedere. Saluti! – drkstr1

+0

Ho provato sia questa che la risposta di @Clodoaldo Neto, l'unione interna è stata ~ 50% più veloce nel mio caso –