2012-12-19 2 views
8

Ich erhalte Duplikate, wenn ich zwei LINKE VERBINDUNGEN mache, um zum "event_name" in meinem Beispiel unten zu gelangen. Ich bekomme 112 Fälle damit auf diese Weise eingerichtet. Wenn ich jedoch die 2 LINKEN VERBINDUNGSLINIEN los werde und die Abfrage ausführe, erhalte ich die richtigen 100 Datensätze ohne Duplikate. Ich habe versucht DISTINCT mit dem Code unten, aber ich bekomme immer noch 112 mit Duplikaten.So vermeiden Sie Duplikate in Sql-Abfrage über drei verbundene Tabellen

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' 

Wie kann ich angeben, dass ich nur die genauen 100 Fälle von „Fällen“ werden soll, und dass ich etwas nicht aus den Tabellen will in der keine Zeilen mehr produzieren verbindet?

Danke!

+1

Wie Tabellen verwandt? 1: N von 'cases' zu' middle_table'? Kannst du uns etwas darüber erzählen? –

+0

könnten Sie einige Testdaten bereitstellen? [sql-fiddle] (http://www.sqlfiddle.com) ist großartig dafür. – Nico

+1

In meinem Fall erhielt ich Dubletten aufgrund der Teilnahme an einer Eins-zu-viele-Verbindung.Die einzige Lösung, die ich finden konnte, war die Verwendung von Unterabfragen. A hat viele Bs. B hat viele Cs und viele Ds. D hat viele Es und viele Fs. Ich musste alle Bs holen (die einer Suchzeichenkette entsprechen), während auch alle in Verbindung stehenden Cs, Es und Fs für jede Übereinstimmung zusammengefasst werden. Ich habe einen äußeren Join verwendet, um ABC zu erhalten, und dann zwei Subabfragen verwendet, um DE und DF zu aggregieren. – bambams

Antwort

7

Sie benötigen eine ON-Klauseln zu verlängern, um einen Zustand zu enthalten, so dass für jeden Eintrag in cases dort in middle_table nur ein Eintrag ist, der die Bedingung übereinstimmt und dass für jeden Eintrag in middle_table gibt es nur einen Eintrag in event:

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

Sie können natürlich DISTINCT verwenden. Wenn das nicht funktioniert, bedeutet dies, dass sich Ihre Ergebnisse in den Feldern cases.id, cases.date, cases.name und event.event_name unterscheiden. Untersuchen Sie die Ergebnisse und entscheiden Sie, welche Einträge Sie wegwerfen möchten, und fügen Sie diese Bedingung in Ihre ON-Klausel ein.

+0

Hallo AndreKR, so wie ich in JohnLBevans Post unten erwähnt habe: Es ist mir egal, welches Kind ich fallen lasse, da sie identisch sind. Können Sie eine theoretische Bedingung geben? Ich verstehe gerade jetzt, dass die Funktion Max bedeutet "gibt den größten Wert der ausgewählten Spalte". Gibt es eine einfache Möglichkeit, nur das auf einem ID-Feld in einer oder beiden verbundenen Tabellen zu verwenden? – Chain

+0

Um dies zu tun, müssen Sie eine dieser drei Techniken verwenden: http://dev.mysql.com/doc/refman/5.5/en/example-maximum-column-group-row.html Aber wenn sie wirklich identisch waren, DISTINCT hätte sie weggefiltert. – AndreKR

+0

Beachten Sie, dass der obige Link für MySQL spezifisch ist, aber wahrscheinlich auch mit anderen Systemen funktioniert. Sie sollten immer angeben, welches DBMS Sie in Ihrer Frage verwenden. – AndreKR

5

Das Problem besteht darin, dass Sie mehrere Übereinstimmungen in den Tabellen haben, mit denen Sie verbunden sind. Effektiv Ihr Code sagt:

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

Wenn ein Elternteil zwei Kinder hat, erhalten Sie beide; So erscheint der Elternteil zweimal.

Wenn Sie nur die Eltern erhalten möchten, sobald Sie Kompromisse eingehen müssen; Du kannst nicht beide Kinder haben. Entweder eine Aggregatfunktion auf Spalten aus der untergeordneten Tabelle durchführt und eine Gruppe tun, indem sie auf Säulen von der übergeordneten Tabelle, oder verwendet rownumber() over partition by (list,of,parent,columns order by list,of,child,columns) r in einer inneren Rechnung und where r=1 in einer äußeren Anweisung, wie unten:

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 

oder

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

Wie in den Kommentaren erwähnt, wenn das Kind Daten ist genau das gleiche, dies zu tun:

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 

oder (wenn ein paar Felder sind unterschiedlich, aber Sie kümmern sich nicht, was Sie bekommen)

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 macht auch einen guten Vorschlag; d. h. Hinzufügen einer bedingten Logik zu der Verknüpfung, um die Ergebnisse auf maximal ein Kind pro Elternteil zu begrenzen. – JohnLBevan

+0

Hi, ich glaube, ich verstehe das meiste. Ja: In meinem Fall haben einige der Eltern mehrere Kinder ... aber es ist eine Art Redundanz in der mittleren Tabelle oder der Ereignistabelle des Krankenhauses. Grundsätzlich sind beide Kinder bestimmter Eltern genaue Duplikate: also ist mir egal, welches Kind ich suche, weil sie beide gleich sind. – Chain

+0

In diesem Fall ist einer der obigen Punkte gut (die zweite Methode ist wahrscheinlich effizienter). Alternativ können Sie die doppelten Kinder frühzeitig ausfiltern (obwohl ich vermute, dass eine unterschiedliche Aussage nicht funktioniert, gibt es einige Unterschiede bei der Rückgabe auf der Kinderebene, selbst wenn es nur die IDs sind). – JohnLBevan

1

Die Duplikate sind das Ergebnis von mehreren Feldern mit für „middle_table“ und „Ereignis“ für " Fälle". Sie können die Auswahl auf die Werte begrenzen, die die „GROUP BY“ Stichwort durch die Verwendung eindeutig sind (die in der Regel für Sortierfunktionen verwendet wird, wie COUNT und SUM), wie folgt:

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'