2016-04-21 8 views
0

In einer Datenbank zu verstehen, gibt es eine Tabelle mit dem Namen Kategorie:diese SQL-LEFT JOIN (mit IS NULL) Beispiel

CREATE TABLE category(
     category_id INT AUTO_INCREMENT PRIMARY KEY, 
     name VARCHAR(20) NOT NULL, 
     parent INT DEFAULT NULL 
); 

Es wurde geschaffen, eine Angrenzend Liste Modellbaum zu machen. Hier ist, was in der Tabelle ist derzeit:

enter image description here

In diesem Beispiel (Sie den Quelle-Link unten finden), der folgende SQL-Code verwendet wurde, die „Blatt“ Elemente in der Tabelle zu erhalten , wobei "leaf" -Elemente die Zeilen in der Tabelle sind, die keine andere Zeile hatten, verwenden Sie ihre "category_id" in der "parent" -Spalte. Der folgende Code ausgeführt wurde:

SELECT t1.name FROM 
category AS t1 LEFT JOIN category as t2 
ON t1.category_id = t2.parent 
WHERE t2.category_id IS NULL; 

Das Ergebnis des vorherigen SQL-Code gibt dieses Ergebnis:

enter image description here

Zum Beispiel gibt es keine Zeile in der Tabelle, die den Wert 3 innerhalb dem hat Übergeordnete Spalte, daher TUBE (mit category_id == 3) ist ein "Blatt" -Element.

FRAGE: Warum gab dieser SQL-Code logisch dieses Ergebnis? Ich bin froh, dass es das tut, weil es genau das ist, was ich brauchte, aber ich kann mich nicht mit den Gedanken dahinter befassen.


Quelle des Beispiels: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

+1

'Outer-Joins' mit' Null'-Checks sind ein übliches Muster, um zu sehen, ob ein Datensatz in einer Tabelle existiert, in diesem Fall überprüft, ob die 'category_id' ein 'Elternteil' ist. Sehr ähnlich wie 'not exist' oder' not in'. – sgeddes

Antwort

2

Jedes Mal, wenn Sie dieses Muster sehen:

SELECT ... 
FROM  TableA 
LEFT JOIN TableB ON TableA.column = TableB.column 
WHERE  TableB.id is null 

Denken. „Zeilen in TableA finden, die in TableB` nicht existieren

Ihre query bedeutet "finde Kategorien, die kein Kind haben." Es ist einfacher zu verstehen, wenn Sie die WHERE-Klausel entfernen und der Abfrage weitere Spalten hinzufügen:

SELECT  t1.category_id, 
      t1.name, 
      t2.name AS ChildName 
FROM  category AS t1 
LEFT JOIN category as t2 ON t1.category_id = t2.parent 

Hier ist, was in der Abfrage geschieht:

  1. Beginnen Sie mit der category Tabelle, alias es als t1 und t2. Ich werde von nun an auf die Aliase verweisen.
  2. Für jede Zeile in t1, alle Datensätze in t2 finden, dass
  3. Wenn ein t1 Reihe kein Kind hat t1 Reihe als ihre Eltern identifiziert, t2.category_id
  4. null sein wird
  5. Wir haben leider nur für t1 Zeilen filtern möchten, die haben kein Kind
+0

Ok, also bin ich sehr nahe dran zu verstehen! Zeile 1 perfekt, Zeile 2 perfekt, Zeile 3 ** Wenn eine Zeile t1 kein Kind hat, wird t2.category_id null sein ** ist, wo ich verwirrt bin. Haben nicht alle Zellen in der Spalte t2.category_id von Anfang an Werte? – Webeng

+0

Denken Sie, "wenn ich kein Kind für Sie finden kann, werde ich' null' anstelle von 'category_id' Ihres Kindes hinterlassen. –

+0

Also wäre diese Argumentation richtig ?: Die' FROM Kategorie AS t1 LEFT JOIN Kategorie als t2 ON t1.category_id = t2.parent' listet zuerst alle Informationen von t1 auf und fügt nur die Informationen der MATCHING t2-Spalten hinzu. Da einige t1.category_id nicht mit t2.parent übereinstimmen, haben sie NULL-Werte für t2.parent UND t2.category_id. Von dort sagt der Code: 'WHERE t2.category_id ist NULL' (ich will nur diejenigen, die nicht übereinstimmten) und nur die Namenspalte' SELECT t1.name' wollen? Würde das auch bedeuten, dass ich 'WHERE t2.category_id IS NULL;' durch 'WHERE t2.parent_id IS NULL;' ersetzen und das gleiche Ergebnis erhalten könnte? – Webeng

0

ich denke, es wäre einfacher, zu sehen, was geschieht, wenn Sie Ihre Tabelle alias umbenennen:

SELECT tparent.name 
     FROM category AS tparent 
     LEFT JOIN category as tchild 
     ON tparent.category_id = tchild.parent 
    WHERE tchild.category_id IS NULL; 

Jetzt ist es vielleicht einfacher zu sehen, wonach Sie suchen, ist eine Liste aller übergeordneten Kategorienamen, die keine Kinder haben [tchild.category_id IST NULL]