2010-03-28 5 views
19

La mia domanda è abbastanza simile a Restricting a LEFT JOIN, con una variazione.Rimuovi duplicati da SINISTRA OUTER JOIN

Supponendo di avere un tavolo NEGOZIO e un altro tavolo POSIZIONE. La posizione è una sorta di tabella figlio della tabella SHOP, che ha due colonne di interesse, una è una chiave di divisione (chiamandola solo CHIAVE) e un numero "NEGOZIO". Questo corrisponde al numero "NO" nella tabella SHOP.

Ho provato questo join esterno sinistro:

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

ma sto ottenendo un sacco di duplicati in quanto ci sono molte posizioni che appartengono ad un unico negozio. Voglio eliminarli e ottenere solo un elenco di voci "negozio, chiave" senza duplicati.

I dati sono corretti, ma i duplicati appaiono come segue:

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

Vorrei i dati di apparire come questo, invece:

SHOP  KEY 
1  XXX 
2  YYY 
3  ZZZ etc. 

tavolo SHOP:

NO 
1  
2  
3  

LOCATION tabella:

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

Non dovresti ricevere duplicati, tuttavia, come hai affermato, puoi ottenere più di una chiave per un negozio se hai più di un record di posizione per il negozio. Per favore spiega o fai un esempio di cosa intendi con "duplicato". –

+1

@Marcus All'inizio pensavo lo stesso, ma suppongo che più sedi possano avere la stessa chiave di divisione. –

+0

@Marcus & Martin: ah non penso di averlo chiarito. Sì, più sedi possono avere e hanno una stessa chiave di divisione. (In pratica, divnkey è il genitore del negozio, quindi la gerarchia va come questa Divnkey> Negozio> posizione). Sto cercando di compilare la tabella del negozio con i dati della chiave della divisione appropriata. Può sembrare strano, ma è un processo unico e stavo cercando di generare script di aggiornamento per la tabella SHOP dai dati della tabella di LOCATION - tramite un comando select 'update shop set divnkey = ....'. Non volevo complicare la domanda, quindi metti una selezione semplice. –

risposta

24

È necessario 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 per usare 'GROUP BY', che è equivalente a' DISTINCT' su Oracle http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::1111_QUESTION_ID:32961403234212 ma a volte può essere più veloce su altri motori, ad es Postgres (usando gli hash invece di ordinare.) – vladr

+0

Ok, mi hai fatto sentire davvero stupido. Questo funziona perfettamente. Grazie. Ma qualsiasi commento aggiuntivo sul perché il gruppo è richiesto a tutti quando il sinistro esterno dovrebbe prendersi cura di questo. Come in sto cercando di capire come funziona l'esterno sinistro. –

+0

@Kaushik: A LEFT OUTER JOIN non è equivalente né implica un GROUP BY o DISTINCT. LEFT JOIN prende tutte le righe dalla tabella sinistra (prima) e unisce tutte le righe dalla tabella destra (seconda) in cui la condizione di join è soddisfatta. In un join * outer * sinistro, se non ci sono dati trovati nella tabella di destra che corrisponde ai dati della tabella di sinistra, i dati della tabella di sinistra vengono ancora restituiti con NULL inseriti per tutti i dati della tabella di destra. Nessun raggruppamento è espresso o implicito. Personalmente avrei usato DISTINCT come penso che specifichi più chiaramente l'intento, ma YMMV. –

7

EDIT A seguito dell'aggiornamento nello scenario

penso che si dovrebbe essere in grado di fare questo con una semplice query sub (anche se non ho ancora testato questo contro un Database Oracle). Qualcosa di simile a quanto segue

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

È possibile che questo genererà un errore in caso di un negozio di essere associati con le posizioni che sono più divisioni.

Se si desidera semplicemente ignorare questa possibilità e selezionarne una arbitraria in tal caso si potrebbe usare

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

Bello :) Ecco perché è importante ottenere più di un angolo. Grazie Martin, la tua soluzione soddisfa sicuramente il mio requisito di base (ma l'altra risposta si occupa in particolare della rimozione dei duplicati, quindi dovrò contrassegnarla). Cheers –

6

Ho avuto questo problema, ma non ho potuto utilizzare GROUP BY per risolvere il problema perché stavo anche restituendo campi di testo di tipo. (Lo stesso vale per l'uso di DISTINCT).

Questo codice mi ha dato duplica:

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 

ho riparato riscrivendo è così:

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 

Come si può vedere che non mi importava circa i dati all'interno della seconda tabella (thing_y), solo se ci sono state corrispondenze maggiori di zero su rpt_id al suo interno. (FYI: rpt_id non era anche la chiave primaria sulla 1a tabella, master_x).