2012-12-19 15 views
8

Ricevo i duplicati quando eseguo due JOIN SINISTRO per ottenere il "nome_evento" nel mio esempio di seguito. Ottengo 112 casi con esso impostato in questo modo. Tuttavia, se mi sbarazzo delle 2 linee LEFT JOIN ed eseguo la query, ottengo i 100 record corretti senza duplicati. Ho provato DISTINCT con il codice qui sotto, ma ottengo ancora il 112 con i duplicati.Come evitare i duplicati nella query sql su tre tabelle unite

SELECT "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
FROM "cases" 
LEFT JOIN "middle_table" ON "cases"."serial" = "middle_table"."m_serial" 
LEFT JOIN "event" ON "middle_table"."e_serial" = "event"."ev_serial" 
WHERE "cases"."date" BETWEEN '2012-12-11' AND '2012-12-13' 

Come faccio a specificare che io voglio solo le esatte 100 casi di "casi", e che io non voglio niente dalle tabelle in join di produrre qualsiasi più righe?

Grazie!

+1

Come vengono tabelle correlate? 1: N da 'cases' a' middle_table'? Potresti parlarci un po 'di questo? –

+0

potresti fornire alcuni testdata? [sql-fiddle] (http://www.sqlfiddle.com) è perfetto per questo. – Nico

+1

Nel mio caso, stavo ottenendo duplicati a causa dell'adesione a un join uno-a-molti.L'unica soluzione che ho trovato è stata l'utilizzo di sottoquery. A ha molti Bs. B ha molte C e molti D. D ha molti Es e molte F. Avevo bisogno di recuperare tutti i Bs (che corrispondono a una stringa di ricerca), mentre aggregavo anche tutti i relativi C, Es e F per ogni corrispondenza. Ho usato un outer join per ottenere l'ABC, quindi ho usato due sottoquery per aggregare DE e DF. – bambams

risposta

7

È necessario estendere le clausole ON per includere una condizione in modo che per ogni voce in cases c'è solo una voce nel middle_table che corrisponde la condizione e che per ogni voce nel middle_table c'è solo una voce nel event:

LEFT JOIN middle_table ON cases.serial = middle_table.m_serial AND some_condition 

Ovviamente è possibile utilizzare DISTINCT. Se ciò non funziona significa che i risultati sono tutti diversi nei campi cases.id, cases.date, cases.name e event.event_name. Esaminare i risultati e decidere quale delle voci si desidera eliminare e includere tale condizione nella clausola ON.

+0

Ciao AndreKR, così come ho detto sul post di JohnLBevan qui sotto: Non mi importa di quale figlio scenda perché sono identici. Sareste in grado di fornire una condizione teorica? Ho appena capito che la funzione Max significa "restituisce il valore più grande della colonna selezionata". C'è un modo semplice di usarlo su un campo id in una o entrambe le tabelle unite? – Chain

+0

Per fare ciò è necessario utilizzare una di queste tre tecniche: http://dev.mysql.com/doc/refman/5.5/en/example-maximum-column-group-row.html Ma se fossero davvero identici, DISTINCT li avrebbe filtrati. – AndreKR

+0

Nota che il link sopra è specifico per MySQL ma probabilmente funziona anche con altri sistemi. Dovresti sempre indicare quale DBMS stai usando nella tua domanda comunque. – AndreKR

5

Il problema è che hai più corrispondenze nelle tabelle con cui ti sei lasciato unito. Effettivamente il tuo codice dice:

select * 
from parent 
left outer join child on parent.id = child.parentId 

Se un genitore ha due figli, ottieni entrambi; quindi il genitore appare due volte.

Se si desidera ottenere il genitore solo una volta è necessario scendere a compromessi; non puoi avere entrambi i bambini. Eseguire sia una funzione di aggregazione su colonne dalla tabella figlio e fare un gruppo su colonne dalla tabella padre, o utilizzare rownumber() over partition by (list,of,parent,columns order by list,of,child,columns) r in un'istruzione interna e where r=1 in un'istruzione esterno, come di seguito:

select p.id, p.name, max(c.id), max(c.name) --nb: child id and name may come from different records 
from parent p 
left outer join child c on parent.id = child.parentId 
group by p.id, p.name 

o

select * 
from 
(
    select p.id, p.name, c.id, c.name 
    , rownumber() over (partition by p.id order by c.id desc) r 
    from parent p 
    left outer join child c on parent.id = child.parentId 
) x 
where x.r = 1 

UPDATE

Come accennato nei commenti, se i dati bambino è esattamente la stessa cosa si può fare questo:

select p.id, p.name, c.name 
from parent p 
left outer join 
(
    select distinct c.parentId, c.name 
    from child 
) c on parent.id = child.parentId 

o (se alcuni campi sono diversi, ma non si cura che si ottiene)

select p.id, p.name, c.id, c.name 
from parent p 
left outer join 
(
    select max(c.id) id, c.parentId, c.name 
    from child 
    group by c.parentId, c.name 
) c on parent.id = child.parentId 
+0

ps. @AndreKR è anche un buon suggerimento; Ad esempio, aggiungi la logica condizionale al join per limitare i risultati a un massimo di un figlio per genitore. – JohnLBevan

+0

Ciao, penso di capirlo molto. Sì: nel mio caso, alcuni genitori hanno più figli ... ma è una sorta di ridondanza nel tavolo centrale degli ospedali o nella tabella degli eventi. Fondamentalmente, entrambi i figli di alcuni genitori sono duplicati esatti: quindi non mi interessa quale bambino scelgo, perché sono entrambi gli stessi. – Chain

+0

In tal caso, uno dei due è buono (il secondo metodo è probabilmente più efficiente). In alternativa puoi filtrare i bambini duplicati nelle prime fasi (anche se ho il sospetto che una dichiarazione distinta non funzioni, ci sono alcune differenze in ciò che viene restituito a livello di figlio, anche se sono solo gli id). – JohnLBevan

1

I duplicati sono il risultato di avere più campi per "middle_table" e "evento" per " casi". È possibile limitare le selezioni ai valori che sono unici utilizzando la parola chiave "GROUP BY" (che di solito è utilizzato per funzioni, come ad esempio COUNT e SUM fascicolazione), come segue:

SELECT "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
FROM "cases" 
LEFT JOIN "middle_table" ON "cases"."serial" = "middle_table"."m_serial" 
LEFT JOIN "event" ON "middle_table"."e_serial" = "event"."ev_serial" 
GROUP BY "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
WHERE "cases"."date" BETWEEN '2012-12-11' AND '2012-12-13' 
Problemi correlati