/ / MySQL Wie finde ich Eltern mit exakten Kindern? - MySQL, SQL

MySQL, wie man Eltern mit exakten Kindern findet? - MySQL, SQL

MySQL 5.5

übergeordnete Tabelle: id | Fakten
Kindertisch: parent_id | foreign_key | Fakten

Nun möchte ich Eltern finden, die eine bestimmte Anzahl von Kindern haben, nicht mehr und nicht weniger. So etwas wie:

SELECT t1.`id`
from `parent_table` t1
LEFT JOIN `child_table` t2 ON t1.id=t2.parent_id
WHERE t2.`fk` = 1
AND t2.`fk` = 3
AND t2.`fk` = 5
AND t2.`fk` = 7
AND t2.`fk` = 9

Bei diesem Satz von Kindern wird dies jedoch auch eine übergeordnete Aufzeichnung: 1,2,3,5,7,9. Und ich will nur die Eltern, die das haben die genaue Menge von Kindern: 1,3,5,7,9.

Gibt es einen Weg?

BEARBEITEN: child.parent_id und child.fk sind beide nicht eindeutig. Kind.fk ist ein Fremdschlüssel, der mit einer anderen Tabelle verknüpft ist. ("Viele-zu-Viele-Beziehung") Es ist also durchaus möglich, dass ein Elternteil Kinder 1,2,3,5,7,9 hat. Mein ganzer Grund für diese Abfrage ist zu versuchen zu vermeiden, dass ein neues übergeordnetes Element für 1,3,5,7,9 erstellt wird, wenn ein solches bereits vorhanden ist.

Antworten:

2 für die Antwort № 1

Vorausgesetzt, dass child.id ist für jeden einzigartig child.parent_id.

SELECT  a.id, a.facts
FROM    parent a
INNER JOIN child b
ON a.id = b.parent_ID
WHERE   b.id IN (1,3,5,7,9) AND        -- <<== list all ChildID here
EXISTS                         -- <<== this part checks if the parent_ID
(                              --           present on the EXISTS clause
SELECT  parent_ID          --           which only filters parents
FROM    child c            --           with 5 children
WHERE   b.parent_ID = c.parent_ID
GROUP   BY parent_ID
HAVING  COUNT(*) = 5       -- <<== total number of children
)
GROUP   BY a.id, a.facts
HAVING  COUNT(*) = 5                   -- <<== total number of children

1 für die Antwort № 2

Dieses Problem wird als (genaue) Beziehungsaufteilung bezeichnet. Dieser Artikel enthält viele nützliche Informationen und Erklärungen: Geteilt wir stehen: Die SQL der relationalen Division.

Ein Weg, um es zu lösen:

SELECT p.id AS parent_id
FROM parent AS p
WHERE EXISTS
( SELECT * FROM child AS c
WHERE c.fk = 1 AND c.parent_id = p.id)
AND EXISTS
( SELECT * FROM child AS c
WHERE c.fk = 3 AND c.parent_id = p.id)
AND EXISTS
( SELECT * FROM child AS c
WHERE c.fk = 5 AND c.parent_id = p.id)
AND EXISTS
( SELECT * FROM child AS c
WHERE c.fk = 7 AND c.parent_id = p.id)
AND EXISTS
( SELECT * FROM child AS c
WHERE c.fk = 9 AND c.parent_id = p.id)
AND NOT EXISTS
( SELECT * FROM child AS c
WHERE c.fk NOT IN (1,3,5,7,9) AND c.parent_id = p.id) ;

Und noch ein Link zu einer ähnlichen Frage hierStackOverflow, in dem Sie mehr als 10 verschiedene Lösungen finden (Hinweis: nicht für die genaue Aufteilung, sondern für die Aufteilung mit Rest) und Leistungstests (für Postgres): Wie filtert man SQL-Ergebnisse in einer durchgeknallten Beziehung?


1 für die Antwort № 3
SELECT   parent_id
FROM     child_table
GROUP BY parent_id
HAVING   SUM(id IN (1,3,5,7,9)) = COUNT(*)
AND COUNT(DISTINCT id) = 5

1 für die Antwort № 4

Ähnlich wie die Lösung von eggyal, aber ich dachte nur, ich würde sie als Alternative einwerfen, da sie über RDBMS tragbarer sein sollte;

SELECT c.parent_id
FROM child_table c
GROUP BY c.parent_id
HAVING SUM(CASE WHEN c.id IN (1,3,5,7,9) THEN 1 ELSE -1 END) = 5

5 die genaue Anzahl von Kindern in der IN-Klausel sein, die übereinstimmen soll (in diesem Fall alle)

Dieser Wille Nur mit bestimmten Kindern arbeitenWenn es Duplikate gibt, wird es brechen.

Eine SQLFiddle zum Testen mit.