SQL search depth/breadth first

Extra-Spalte zum Sortieren des Ergebnisses einer rekursiven Abfrage erzeugen


Apache DerbyBigQueryDb2 (LUW)H2MariaDBMySQLOracle DBPostgreSQLSQL ServerSQLite20072009201120132015201720192021⊘ 3.5.7 - 3.43.0⊘ 2008R2 - 2022✓ 14 - 16⊘ 8.3 - 13✓ 11gR2 - 21ca⊘ 11gR1⊘ 5.0 - 8.0.34⊘ 5.1 - 10.11⊘ 1.4.191 - 2.2.220⊘ 9.7 - 11.5.8⊘ 2.0⊘ 10.15.1.3 - 10.16.1.1
  1. Geringe Abweichung: Inhalt der <sequence column>

Die Search-Klausel von With Recursive erzeugt eine Spalte, mit der das Ergebnis entsprechend einer Tiefensuche oder Breitensuche sortiert werden kann.

Die Search-Klausel folgt unmittelbar auf ein rekursives With-Element – sogar noch vor der Cycle-Klausel. Sie legt die primäre Reihenfolge mit den Schlüsselworten Depth First (Tiefe zuerst) oder Breadth First (Breite zuerst) fest. In der darauffolgenden, zwingend erforderlichen By-Klausel wird durch eine Liste von Ausdrücken die Reihenfolge pro Ebene festgelegt. Zuletzt weist die Set-Klausel der so erzeugten Sequenzspalte einen Namen zu.

WITH RECURSIVE
     categories (category_id, parent, name)
  AS ( SELECT *
         FROM product_categories
        WHERE parent IS NULL
    UNION ALL
       SELECT pc.*
         FROM categories AS parent
         JOIN product_categories pc
           ON pc.parent = parent.category_id
     )
SEARCH DEPTH FIRST BY name SET seq_col
SELECT category_id, name
  FROM categories
 ORDER BY seq_col

Beachte, dass die Search-Klausel nicht festlegt, in welche Reihenfolge die Zeilen aus der rekursiven Abfrage kommen.0Stattdessen erzeugt sie seine Spalten, die in einer Order By-Klausel verwendet werden kann.

Das obere Beispiel durchwandert eine Hierarchie, wie zum Beispiel die unten dargestellte, vom Wurzelknoten zu den Blattknoten. Die Order By-Klausel in der letzten Zeile nutzt die durch die Search-Klausel erzeugte Sequenzspalte seq_col um die entsprechende Reihenfolge tatsächlich herzustellen. Dabei ist seq_col wirklich nur ein Spaltenname. Man kann ihn auch in die Select-Klausel aufnehmen, um sich den Inhalt anzusehen – oder select * verwenden. Natürlich kann man in der Order By-Klausel auch andere Spalten verwenden oder Asc/Desc und Nulls First/Last-Angaben machen.

All GoodiesTypesBrandsBooksMugs & coStickersModern SQLUse The Index, Luke

Egal ob man eine Tiefe-zuerst oder eine Breite-zuerst Reihenfolge wählt, die Zeilen aus dem Initialisierungszweig der Rekursion haben in der Sequenzspalte immer den kleinsten Wert. Das heißt, dass man sie bei einer aufsteigenden Reihenfolge wie im Beispiel oben zuerst erhält. Konkret ist das der Wurzelknoten: All Goodies.

Die nächste Zeile ist – wiederum in beiden „Zuerst“-Fällen – das erste Kind auf der zweiten Ebene. Das ist allerdings nicht Types, sondern Brands, da die Angabe by name die Reihenfolge in der Ebene festlegt.

Hinweis in eigener Sache

Ich biete SQL Schulungen, Optimierung und Beratung an. Auch der Kauf meines Buches „SQL Performance Explained“ (ab €9,95) unterstützt meine Arbeit an dieser Webseite.

Danach unterscheiden sich die Reihenfolge zwischen Depth First und Breadth First. Depth first, liefert zuerst die tieferen Knoten. Das sind Modern SQL und Use The Index, Luke, in dieser Reihenfolge. Erst danach folgt der Nachbarknoten Types und dessen Kinder.

Breadth First liefert den Nachbarknoten Types jedoch noch vor den Knoten der dritten Ebene. Erst nach allen Knoten der zweiten Ebene folgen jene der dritten – in der durch die By-Klausel festgelegte Reihenfolge. Konkret: Books, Modern SQL, Mugs & co, Stickers, Use The Index, Luke. Beachte, dass die Geschwister nicht beieinanderbleiben. Die Kinder von Brands und Types kommen aufgrund der By name-Angabe entsprechend Ihrem Namen durcheinander.

Nennenswerte Erweiterungen

Standard SQL erlaubt keine Asc/Desc oder Nulls First/Last-Angaben in der By-Klausel von Search.1

SEARCH DEPTH FIRST BY name DESC SET seq_col

Daher ist das Umdrehen der Pro-Ebene-Reihenfolge in Standard-SQL nicht möglich. Da das jedoch eine nachvollziehbare Anforderung ist, gibt es Systeme, die solche Angaben unterstützen.

Oracle DBPostgreSQLsearch … by … asc/descsearch … by … nulls first/last

Inhalt der Sequenzspalte

Der SQL-Standard definiert die Search-Klausel anhand einer syntaktischen Transformation, die die Sequenzspalte mit Zeilenwerten (Breadth First) oder einem Array aus Zeilenwerten (Depth First) befüllt. Sortiert man anhand dieser Werte, erhält man die festgelegte Reihenfolge.2 Daraus folgt aber, dass die von der Order By-Klausel gewohnten Optionen nicht zur Verfügung stehen, da sie nicht in den Zeilenwerten untergebracht werden können.3 Daher ist es vermutlich kein Zufall, dass ausgerechnet jene Systeme, die die Order By-Optionen auch in Search…By erlauben, in der Sequenzspalte nicht die vom Standard vorgesehenen Zeilenwerte liefern, sondern eine einfache Ordnungszahl.

Oracle DBPostgreSQLNormkonformOrdnungszahl

Normative Referenzen

Die Search-Klausel ist in ISO/IEC 9075-2:2023 §7.18 als Teil des optionalen Features T131, „Recursive query“ definiert.

20 Jahre SQL-Evolution kann man nicht an einem Tag nachholen. Abonniere den Newsletter via E-Mail, Twitter oder RSS, um sukzessive aufzuholen und modern-sql.com am Radar zu behalten.

Über den Autor

Foto von Markus Winand

Markus Winand gibt auf modern-sql.com Einblick in SQL und zeigt, wie es von verschiedenen Systemen unterstützt wird. Zuvor machte er use-the-index-luke.com, was er noch immer wartet. Markus kann als Trainer, Sprecher und Berater auf winand.at engagiert werden.

Sein Buch kaufen

Titelbild von „SQL Performance Explained“: Eichhörnchen läuft durchs Grass

Die Essenz: SQL-Tuning auf 200 Seiten

Jetzt Kaufen
(Taschenbuch und/oder PDF)

Sein Training

Markus verwandelt veraltetes SQL-92-Wissen in solides und zeitgemäßes SQL-Know-how

Erfahren Sie mehr»

Fußnoten

  1. Ebenso wenig wird damit der Algorithmus bestimmt, da SQL nach wie vor eine deklarative Sprache ist.

  2. ISO/IEC 9075-2:2023 §7.18: In der BNF nicht vorgesehen. Nicht zu verwechseln mit den entsprechenden Angaben in der Order By-Klausel, die die Sequenzspalte nutzt.

  3. Ich habe jedoch nicht gefunden, wo im Standard der Kleiner-Vergleich für Arrays definiert ist – insbesondere wenn sich die Längen unterscheiden. Die Search-Klausel basiert auf einer kürzer-ist-kleiner Logik, wie sie auch bei Zeichenketten mit einer No-Pad-Collation zur Anwendung kommt (ISO/IEC 9075-2:2023 §8.2 GR 3b).

  4. Da die Sequenzspalte ein zusammengesetzter Wert aus den einzelnen Sortierkriterien ist, könnte man die Komponenten extrahieren und in der Order By-Klausel getrennt verwenden – jeden mit den gewünschten Optionen.

Mit Markus Winand verbinden

Markus Winand auf LinkedInMarkus Winand auf XINGMarkus Winand auf Twitter
„modern SQL“ von Markus Winand ist unter einer Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License lizenziert.
Impressum | Kontakt | KEINE GEWÄHR | Handelsmarken | Datenschutz und DSGVO | CC-BY-NC-ND 3.0 Lizenz