2010-03-28 65 views
19

Câu hỏi của tôi khá giống với Restricting a LEFT JOIN, với một biến thể.Xóa các mục trùng lặp khỏi LEFT OUTER JOIN

Giả sử tôi có một bảng SHOP và một bảng LOCATION. Vị trí là một loại bảng con của bảng SHOP, có hai cột quan tâm, một là một khóa phân chia (gọi nó là KEY) và một số "SHOP". Điều này khớp với Số "KHÔNG" trong bảng SHOP.

tôi đã cố gắng bên ngoài trái này tham gia:

SELECT S.NO, L.KEY 
FROM SHOP S 
LEFT OUTER JOIN LOCATN L ON S.NO = L.SHOP 

nhưng tôi nhận được rất nhiều bản sao vì có rất nhiều địa điểm mà thuộc về một cửa hàng duy nhất. Tôi muốn loại bỏ chúng và chỉ nhận được một danh sách các mục "cửa hàng, khóa" không trùng lặp.

Các dữ liệu là đúng nhưng bản sao xuất hiện như sau:

SHOP  KEY 
1  XXX 
1  XXX 
2  YYY 
3  ZZZ 
3  ZZZ etc. 

Tôi muốn dữ liệu xuất hiện như thế này thay vì:

SHOP  KEY 
1  XXX 
2  YYY 
3  ZZZ etc. 

CỬA HÀNG bảng:

NO 
1  
2  
3  

VỊ TRÍ bảng:

LOCATION SHOP KEY 
    L-1  1 XXX 
    L-2  1 XXX 
    L-3  2 YYY 
    L-4  3 YYY 
    L-5  3 YYY 

(ORACLE 10g Database)

+0

Bạn không nên nhận bất kỳ bản sao nào, tuy nhiên, như bạn đã nêu, bạn có thể nhận được nhiều hơn một khóa cho một cửa hàng nếu bạn có nhiều hơn một bản ghi vị trí cho cửa hàng. Vui lòng giải thích hoặc cho ví dụ về ý nghĩa của bạn bằng "trùng lặp". –

+1

@Marcus Lúc đầu tôi nghĩ tương tự nhưng tôi giả sử rằng nhiều vị trí có thể có cùng một khóa chia. –

+0

@Marcus & Martin: ah tôi không nghĩ rằng tôi đã làm điều này rõ ràng. Có Nhiều vị trí có thể và có cùng một khóa chia. (Nói đúng là divnkey là cha mẹ của cửa hàng. Vì vậy, phân cấp sẽ giống như Divnkey> Shop> location này). Tôi đang cố gắng để điền vào bảng của Shop với dữ liệu khóa phân chia thích hợp. Có thể âm thanh lạ, nhưng đó là một quá trình một thời gian và tôi đã cố gắng để tạo ra các kịch bản cập nhật cho bảng SHOP từ bảng dữ liệu của LOCATION - thông qua lệnh chọn 'update shop set divnkey = ....'. Không muốn làm phức tạp câu hỏi để đặt một lựa chọn đơn giản. –

Trả lời

24

Bạn cần GROUP BY 'S.No' & 'L.KEY'

SELECT S.NO, L.KEY 
FROM SHOP S 
LEFT OUTER JOIN LOCATN L 
ON S.NO = L.SHOP 
GROUP BY S.NO, L.KEY 
+0

+1 để sử dụng 'GROUP BY' tương đương với' DISTINCT' trên Oracle http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212 nhưng đôi khi có thể nhanh hơn trên các công cụ khác, ví dụ Postgres (sử dụng băm thay vì phân loại.) – vladr

+0

Ok bạn vừa mới làm cho tôi cảm thấy thực sự ngu ngốc. Điều này hoạt động hoàn hảo. Cảm ơn. Nhưng bất kỳ ý kiến ​​bổ sung nào về lý do tại sao nhóm được yêu cầu ở tất cả khi bên ngoài bên trái có nghĩa vụ phải chăm sóc điều này. Như trong tôi đang cố gắng để hiểu làm thế nào bên ngoài bên trái thực sự hoạt động. –

+0

@Kaushik: LEFT OUTER JOIN không tương đương với cũng không hàm ý GROUP BY hoặc DISTINCT. Lệnh LEFT JOIN lấy tất cả các hàng từ bảng bên trái (đầu tiên), và tham gia vào tất cả các hàng từ bảng bên phải (thứ hai), nơi điều kiện tham gia được thỏa mãn. Trong một tham gia * bên ngoài * bên trái, nếu không có dữ liệu được tìm thấy trong bảng bên phải khớp với dữ liệu từ bảng bên trái thì dữ liệu bảng bên trái vẫn được trả lại bằng NULL được đặt cho tất cả dữ liệu bảng bên phải. Không có nhóm được thể hiện hoặc ngụ ý. Cá nhân tôi đã sử dụng DISTINCT vì tôi nghĩ rằng nó rõ ràng hơn chỉ định ý định, nhưng YMMV. –

7

EDIT Sau khi cập nhật trong kịch bản của bạn

Tôi nghĩ rằng bạn sẽ có thể làm điều này với một truy vấn phụ đơn giản (mặc dù tôi đã không kiểm tra này chống lại một Cơ sở dữ liệu Oracle). Một cái gì đó như sau

UPDATE shop s 
SET divnkey = (SELECT DISTINCT L.KEY FROM LOCATN L WHERE S.NO = L.SHOP) 

Ở trên sẽ gây ra lỗi trong trường hợp một cửa hàng được liên kết với các vị trí nằm trong nhiều bộ phận.

Nếu bạn chỉ muốn bỏ qua khả năng này và chọn một ai tùy ý trong sự kiện mà bạn có thể sử dụng

UPDATE shop s 
SET divnkey = (SELECT MAX(L.KEY) FROM LOCATN L WHERE S.NO = L.SHOP) 
+0

Nice :) Đây là lý do tại sao điều quan trọng là phải có nhiều hơn một góc. Cảm ơn Martin, giải pháp của bạn chắc chắn nhất đáp ứng yêu cầu cơ bản của tôi (Nhưng câu trả lời khác cụ thể là chăm sóc loại bỏ các bản sao, do đó, sẽ phải đánh dấu một). Chúc mừng –

6

Tôi cũng gặp sự cố này nhưng tôi không thể sử dụng GROUP BY để khắc phục sự cố vì tôi cũng đã trả lại các trường loại TEXT. (Tương tự, dùng DISTINCT).

Mã này đã cho tôi bản sao:

select mx.*, case isnull(ty.ty_id,0) when 0 then 'N' else 'Y' end as inuse 
from master_x mx 
left outer join thing_y ty on mx.rpt_id = ty.rpt_id 

tôi cố định nó bằng cách viết lại nó thusly:

select mx.*, 
case when exists (select 1 from thing_y ty where mx.rpt_id = ty.rpt_id) then 'Y' else 'N' end as inuse 
from master_x mx 

Như bạn có thể thấy tôi không quan tâm về các dữ liệu trong bảng 2 (thing_y), chỉ cho dù có lớn hơn không phù hợp trên rpt_id bên trong nó. (FYI: rpt_id cũng không phải là khóa chính trên bảng 1, master_x).

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