2010-03-28 7 views
19

Moje pytanie jest podobne do Restricting a LEFT JOIN, z odmianą.Usuwanie duplikatów z LEFT OUTER DOŁĄCZ

Zakładając, że mam stół SKLEP i kolejną lokalizację LOCATION. Lokalizacja jest rodzajem tabeli podrzędnej tabeli SKLEP, która ma dwie kolumny zainteresowania, jedna to klucz podziału (nazywając go tylko kluczem) i numer "SKLEP". Dopasowuje się do numeru "NIE" w tabeli SKLEP.

Próbowałem to lewe sprzężenie zewnętrzne:

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

ale dostaję wiele duplikatów, ponieważ istnieje wiele miejsc, które należą do jednego sklepu. Chcę je wyeliminować i po prostu uzyskać listę wpisów "sklep, klucz" bez duplikatów.

Dane są poprawne, ale duplikaty wyglądać następująco:

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

Chciałbym dane, aby wyglądał następująco:

SHOP  KEY 
1  XXX 
2  YYY 
3  ZZZ etc. 

stół SHOP:

NO 
1  
2  
3  

MIASTO tabela:

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

(Oracle Database 10g)

+0

Nie powinieneś dostawać żadnych duplikatów, ponieważ, jak stwierdzono, możesz otrzymać więcej niż jeden klucz do sklepu, jeśli masz więcej niż jeden rekord lokalizacji dla sklepu. Proszę wyjaśnić lub podać przykład tego, co rozumie się przez "duplikowanie". –

+1

@ Marcus Z początku myślałem, że to samo, ale zakładam, że wiele lokalizacji może mieć ten sam klucz podziału. –

+0

@Marcus & Martin: ah nie sądzę, że to wyjaśniłem. Tak Wiele lokalizacji może i ma ten sam klucz podziału. (Ściśle mówiąc divnkey jest nadrzędnym elementem sklepu, więc hierarchia przebiega w taki sposób, jak Divnkey> Shop> location). Próbuję wypełnić tabelę Sklepu odpowiednimi danymi klucza podziału. Może brzmi to dziwnie, ale jest to proces jednorazowy i próbowałem wygenerować skrypty aktualizacji dla SKLEPU z danych LOCATION tabeli - za pomocą komendy "update shop set divnkey = ....". Nie chciał komplikować pytania, więc po prostu wybierz. –

Odpowiedz

24

Trzeba 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 za użycie opcji "GROUP BY", która jest odpowiednikiem 'DISTINCT' w Oracle http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212, ale czasami może być szybszy w innych silnikach np Postgres (używając skrótów zamiast sortowania.) – vladr

+0

OK, właśnie poczułam się głupio. To działa idealnie. Dzięki. Ale dodatkowe komentarze na temat przyczyn, dla których grupa jest wymagana, gdy lewa strona zewnętrzna ma to zająć. Jak w próbuję zrozumieć, jak lewy zewnętrzny naprawdę działa. –

+0

@Kaushik: LEWY ZEWNĘTRZNY DOŁĄCZ nie jest równoważny ani nie implikuje GROUP BY lub DISTINCT. LEFT JOIN przyjmuje wszystkie wiersze z lewej (pierwszej) tabeli i łączy we wszystkich wierszach z prawej (drugiej) tabeli, w której spełniony jest warunek łączenia. W lewym * sprzężeniu * zewnętrznym, jeśli w prawej tabeli nie ma danych, które pasują do danych z lewej tabeli, dane z lewego stołu są nadal zwracane z wartościami NULL umieszczonymi dla wszystkich danych z prawej tabeli. Żadne ugrupowanie nie jest wyrażone ani dorozumiane. Osobiście użyłbym DISTINCT, ponieważ myślę, że wyraźniej określa zamiar, ale YMMV. –

7

EDIT Po aktualizacji scenariusza

Myślę, że powinieneś być w stanie zrobić to z prostej kwerendy sub (choć nie testowałem tego Przeciwko Baza danych Oracle). Coś podobnego do następującego: Powyższe spowoduje błąd w przypadku powiązania sklepu z lokalizacjami znajdującymi się w wielu działach.

Jeśli chcesz po prostu zignorować tę możliwość i wybrać dowolny jeden w tym przypadku można użyć

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

Nice :) Dlatego ważne jest, aby uzyskać więcej niż jeden kąt. Dzięki Martin, twoje rozwiązanie z całą pewnością zaspokaja moje podstawowe wymagania (ale inna odpowiedź w szczególności dba o usunięcie duplikatów, więc będzie musiał to zaznaczyć). Pozdrawiamy: –

6

Miałem ten problem, ale nie mogłem użyć GROUP BY, aby to naprawić, ponieważ również zwróciłem pola typu TEXT. (To samo dotyczy użycia DISTINCT).

Kod ten dał mi powiela:

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 

Naprawiłem go przez przepisywanie go 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 

Jak widać nie dbałem o danych w tabeli 2 (thing_y), czy było więcej niż zero dopasowań na rpt_id w nim. (FYI: rpt_id również nie był kluczem podstawowym na pierwszej tabeli, master_x).