2013-07-30 6 views
5

Ich versuche zu verstehen, wie eine Abfrage erstellt wird, um einige Ergebnisse basierend auf einem inneren Join herauszufiltern.So verhindern Sie Duplikate mit innerer Join-Abfrage (Postgres)

Betrachten Sie die folgende Daten:

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 

Ich möchte alle formulation_batch Datensätze mit einem project_id von 1 wählen, und hat eine formulation_batch_component mit einem component_id von 1 oder 2. So betreibe ich die folgende Abfrage:

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)) 

Allerdings gibt diese einen doppelten Eintrag:

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

Gibt es eine Möglichkeit, diese Abfrage so zu ändern, dass ich nur die eindeutigen recentment_batch-Datensätze zurückbekomme, die den Kriterien entsprechen?

Beispiel:

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

Vielen Dank für Ihre Zeit!

Antwort

7

Eine Möglichkeit wäre distinct zu verwenden:

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

Danke, ich habe deutlich unterschieden. Es ist nicht die beste Leistung, aber immer noch besser, als es auf der Softwareebene zu filtern. – drkstr1

10

In diesem Fall ist es möglich, die distinct vor dem join möglicherweise macht es performanter anzuwenden:

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 

Beachten Sie, wie Alias ​​verwenden für die Tabellennamen, um die Abfrage klarer zu machen. Auch dann in Betreiber ist sehr praktisch. Die Verwendung von Anführungszeichen mit diesen Bezeichnern ist nicht erforderlich.

+0

Vielen Dank für die Idee zur Optimierung. Die Abfrage wird tatsächlich von einem ORM generiert, aber ich denke, dass ich eine Möglichkeit habe, sie so zu implementieren (ähnlich wie ich sie geändert habe, um sie in der äußeren Abfrage zu unterscheiden). – drkstr1

+0

In meinen Tests, wie oben innerjoining war auch schneller als die formulationbatch_ids in einem mit where-Klausel, dh:. 'fb select * von formulation_batch fb wo fb.project_id = 1 UND fb.id IN ( formulationbatch_id wählen from rezeptur_batch_komponente where component_id in (1, 2) ) ' –

2

Ich weiß, die Frage fragt, wie Duplikate mit inneren Join verhindert werden, könnte aber eine IN-Klausel im Prädikat verwenden.

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

Dies ist die beste Lösung für die Frage, die ich stellen wollte. Prost! – drkstr1

+0

Ich testete diese und @Clodoaldo Neto's Antwort, innerer Beitritt war ~ 50% schneller in meinem Fall –

Verwandte Themen