2013-07-30 28 views
5

Tôi đang cố gắng hiểu cách tạo truy vấn để lọc ra một số kết quả dựa trên kết nối bên trong.cách ngăn trùng lặp với truy vấn tham gia bên trong (Postgres)

Hãy xem xét các dữ liệu sau:

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 

Tôi muốn chọn tất cả các hồ sơ formulation_batch với một PROJECT_ID trong tổng số 1, và có một formulation_batch_component với một component_id trong tổng số 1 hoặc 2. Vì vậy, tôi chạy truy vấn sau đây:

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

Tuy nhiên, điều này trả về một mục trùng lặp:

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

Có cách nào để sửa đổi truy vấn này để tôi chỉ lấy lại các bản ghi formulation_batch duy nhất phù hợp với tiêu chí?

EG:

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

Cảm ơn thời gian của bạn!

Trả lời

7

Một cách sẽ được sử dụng 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

Cảm ơn, tôi đã quên về sự khác biệt. Nó không phải là hiệu suất tốt nhất khôn ngoan, nhưng vẫn tốt hơn so với lọc nó ra ở cấp phần mềm. – drkstr1

10

Trong trường hợp này chúng ta có thể áp dụng các distinct trước join có thể làm cho nó performant hơn:

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 

Chú ý cách sử dụng bí danh cho các tên bảng để làm cho truy vấn rõ ràng hơn. Ngoài ra sau đó in nhà điều hành là rất tiện dụng. Việc sử dụng dấu ngoặc kép với các số nhận dạng đó là không cần thiết.

+0

Cảm ơn bạn đã có ý tưởng về tối ưu hóa. Truy vấn thực sự được tạo bởi một ORM, nhưng tôi nghĩ rằng tôi có một cách để thực hiện nó như thế này thay vào đó (theo cùng cách tôi đã sửa đổi nó để chọn khác biệt trên truy vấn bên ngoài). – drkstr1

+0

Trong các thử nghiệm của tôi, innerjoining như trên cũng là nhanh hơn bằng cách sử dụng formulationbatch_ids trong một mệnh đề where, ví dụ:. 'chọn fb * từ formulation_batch fb nơi fb.project_id = 1 AND fb.id IN ( chọn formulationbatch_id từ formulation_batch_component trong đó component_id trong (1, 2) ) ' –

2

Tôi biết câu hỏi sẽ hỏi cách ngăn trùng lặp với tham gia bên trong nhưng có thể sử dụng mệnh đề IN trong biến vị ngữ.

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

Đây là giải pháp tốt nhất cho câu hỏi mà tôi đang cố hỏi. Chúc mừng! – drkstr1

+0

Tôi đã thử nghiệm cả câu trả lời này và câu trả lời của @Clodoaldo Neto, việc gia nhập bên trong nhanh hơn ~ 50% trong trường hợp của tôi –

Các vấn đề liên quan