2012-12-19 13 views
8

Otrzymuję duplikaty, gdy wykonuję dwa POŁĄCZENIA W LEWO, aby dostać się do "nazwy zdarzenia" w poniższym przykładzie. Dostaję 112 skrzynek z tym ustawionym w ten sposób. Jednakże, jeśli pozbędę się 2 linii LEFT JOIN i uruchomię zapytanie, otrzymam właściwe 100 rekordów bez duplikatów. Próbowałem DISTINCT z poniższym kodem, ale nadal otrzymuję numer 112 z duplikatami.Jak uniknąć duplikatów zapytań sql w trzech połączonych tabelach

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' 

Jak mogę określić, że chcę tylko dokładnie 100 przypadki z „przypadków”, a ja nie chcę niczego z tabel w przystępuje do produkcji kolejnych wierszy?

Dzięki!

+1

Jak tabele powiązane? 1: N od 'case' do' middle_table'? Czy możesz nam coś o tym powiedzieć? –

+0

czy możesz podać kilka danych testowych? [sql-fiddle] (http://www.sqlfiddle.com) jest świetny do tego. – Nico

+1

W moim przypadku otrzymywałem duplikaty z powodu dołączenia do grupy jeden-do-wielu.Jedynym rozwiązaniem, które mogłem znaleźć, było użycie pod-zapytań. A ma wiele Bs. B ma wiele Cs i wiele Ds. D ma wiele Es i wiele F. Musiałem pobrać wszystkie B (które pasują do łańcucha wyszukiwania), a także agregować wszystkie powiązane C, Es i F dla każdego dopasowania. Użyłem sprzężenia zewnętrznego, aby uzyskać ABC, a następnie użyłem dwóch sub-zapytań do agregacji DE i DF. – bambams

Odpowiedz

7

Trzeba rozszerzyć klauzule dotyczące zawierać warunek tak, że dla każdego wpisu w cases istnieje tylko jeden wpis w middle_table pasujący stan i że dla każdego wpisu w middle_table istnieje tylko jeden wpis w event:

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

Możesz oczywiście użyć DISTINCT. Jeśli to nie zadziała, oznacza to, że wszystkie wyniki są różne w polach cases.id, cases.date, cases.name i event.event_name. Sprawdź wyniki i zdecyduj, które z wpisów chcesz wyrzucić i zawrzyj ten warunek w klauzuli ON.

+0

Cześć AndreKR, tak jak wspomniałem na postu JohnLBevana poniżej: Nie obchodzi mnie, które dziecko upuszczam, ponieważ są one identyczne. Czy byłbyś w stanie podać teoretyczny warunek? Właśnie zrozumiałem, że funkcja Max oznacza "zwraca największą wartość wybranej kolumny". Czy istnieje prosty sposób użycia tego w polu identyfikatora w jednej lub obu połączonych tabelach? – Chain

+0

Aby to zrobić, musisz użyć jednej z tych trzech technik: http://dev.mysql.com/doc/refman/5.5/en/example-maximum-column-group-row.html Ale jeśli były naprawdę identyczne, DISTINCT odfiltrowałoby je. – AndreKR

+0

Należy zauważyć, że powyższy link jest specyficzny dla MySQL, ale prawdopodobnie działa również z innymi systemami. W każdym razie powinieneś zawsze podać, jakiego DBMS używasz w swoim pytaniu. – AndreKR

5

Problem polega na tym, że masz wiele dopasowań w tabelach, z którymi się łączysz. Skutecznie Twój kod mówi:

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

Jeśli rodzic ma dwoje dzieci, otrzymujesz jedno i drugie; więc rodzic pojawia się dwa razy.

Jeśli chcesz zdobyć rodzica tylko wtedy, gdy potrzebujesz kompromisu; nie możesz mieć obu dzieci. Albo wykonać funkcję zbiorczą na kolumnach z tabeli podrzędnej i zrobić grupę przez kolumn z tabeli nadrzędnej lub użyj rownumber() over partition by (list,of,parent,columns order by list,of,child,columns) r w wewnętrznej oświadczenia i where r=1 w zewnętrznym oświadczeniem, takich jak poniżej:

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 

lub

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

Jak wspomniano w komentarzach, jeśli dane dziecko jest dokładnie taka sama możesz to zrobić:

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 

lub (jeśli kilka pola są różne, ale nie dbam o to, które masz)

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 również robi dobrą sugestię; tj. dodaj logikę warunkową do łączenia, aby ograniczyć wyniki do maksymalnie jednego dziecka na rodzica. – JohnLBevan

+0

Cześć, myślę, że rozumiem większość z tego. Tak: w moim przypadku niektórzy rodzice mają wiele dzieci ... ale jest to pewnego rodzaju redundancja w środkowym stole lub stole wydarzeń w szpitalach. Zasadniczo, oba dzieci pewnych rodziców są dokładnymi duplikatami: więc nie obchodzi mnie, które dziecko wybiorę, ponieważ oba są takie same. – Chain

+0

W takim przypadku jedno z powyższych jest dobre (druga metoda jest prawdopodobnie bardziej wydajna). Alternatywnie możesz odfiltrować zduplikowane dzieci wcześnie (choć podejrzewam, że wyraźne stwierdzenie nie działa, istnieją pewne różnice w tym, co jest zwracane na poziomie dziecka, nawet jeśli są to tylko identyfikatory). – JohnLBevan

1

Duplikaty są wynikiem posiadania wielu pól dla „middle_table” i „wydarzenie” za " przypadki ". Można ograniczyć wybory do wartości, które są unikalne za pomocą „grupa przez” słowa kluczowego (który jest zwykle używany do porównywania funkcje, takie jak policzyć i SUM), w następujący sposób:

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' 
Powiązane problemy