Literarisches SQL


Literate programming ist eine von Donald Knuth propagierte Programmiermethode, die – unter anderem – danach strebt, den Quelltext so zu gestalten, dass er wie ein Roman von vorne nach hinten gelesen werden kann.

SQL funktioniert genau umgekehrt: Die Verschachtelung von Unterabfragen führt dazu, dass man zuerst die innerste Abfrage suchen und verstehen muss, um sich von dort aus nach außen arbeiten zu können. Nicht einmal gut gewählte Namen können diesen rekursiven Leseprozess merklich verbessern, weil die Namen den Unterabfragen folgen.

Sogar die Reihenfolge der Klauseln der einfachsten SQL-Abfrage hat eine Vorwärtsabhängikeit: Die Bedeutung der select-Klausel hängt von der from-Klausel ab. Das stellt Entwicklungswerkzeuge sogar vor eine unlösbare Aufgabe: Wenn man select eingibt, ist noch nicht bekannt, auf welche Tabellen zugegriffen wird und daher auch nicht, welche Spalten sichtbar sind. Ohne from-Klausel keine sinnvollen Vorschläge für die select-Klausel.

Mit SQL:1999 wurde zumindest zur Verschachtelung eine Alternative geschaffen: die with-Klausel. Im Zusammenhang mit literarischem SQL hat die with-Klausel zwei wichtige Eigenschaften: (1) Namen kommen zuerst; (2) Unterabfragen können beliebig angeordnet werden.

Namen zuerst

Die Wichtigkeit aussagekräftiger Namen für Softwarekomponenten kann nicht genug betont werden. Aber selbst der beste Name, der die Absicht der Komponente verrät, ist nutzlos, wenn er im entscheidenden Moment nicht ins Auge springt:

SELECT ...
  FROM (SELECT ...
          FROM ...
       ) intention_revealing_name
   ...

Je länger die innere Abfrage wird, desto wichtiger ist ein guter Name, aber desto weiter wird er auch aus dem Blickfeld geschoben. Wie tragisch.

Bei der with-Klausel steht der Name jedoch vor dem Code, so wie bei Funktionsdeklarationen in praktisch jeder anderen Programmiersprache:

WITH intention_revealing_name AS (
     SELECT ...
       FROM ...
     )
SELECT ...
  FROM intention_revealing_name irn
   ...

Als kleines Extra kann man in der from-Klausel noch immer einen kurzen Alias vergeben (irn im Beispiel).

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.

Reihenfolge der menschlichen Logik

Der zweite Aspekt der with-Klausel ist, dass man damit Verschachtelungen in Verkettungen verwandeln kann. Dadurch werden komplexe Abfragen von oben nach unten lesbar.

Eine with-Klausel kann mehrere Abfragen beinhalten. Jede davon kann sich bereits auf zuvor definiert Abfragen aus derselben with-Klausel beziehen. Das ist genau, was man für literarisches SQL braucht.

Das folgende Beispiel skizziert eine literarische Abfrage. Die ersten beiden Definitionen werden nicht einmal gezeigt – die Namen alleine verraten den Zweck:

WITH frequently_bought_together (ordered, suggested, times) AS (
     SELECT ...
     )
   , frequently_bought_shortly_after (ordered, suggested, times) AS (
     SELECT ...
     )
   , product_recommendation (ordered, suggested, times) AS (
     SELECT ordered, suggested, SUM(times)
       FROM (SELECT * FROM frequently_bought_together
              UNION ALL
             SELECT * FROM frequently_bought_shortly_after
            ) frequently_needed_together
      GROUP BY ordered, suggested
      ORDER BY SUM(times) DESC
      FETCH FIRST 1 ROW ONLY 
     )
SELECT *
  FROM product_recommendation

Die Leichtigkeit des Lesens ergibt sich nicht automatisch aus der Von-oben-nach-unten-Struktur. Mit sinnlosen Namen wie x, y, und z wäre die Abfrage noch immer schwer zu verstehen. Erst das Zusammenspiel aus guten Namen und guter Struktur bringt den literarischen Durchbruch.

Wie so oft kann man es natürlich auch mit der Aufteilung in with-Abfragen übertreiben. Kleine Unterabfragen wie frequently_needed_together im Beispiel müssen die Leserbarkeit nicht unbedingt stören. Wichtig ist eine Aufteilung in überschaubare, logisch zusammengehörende Einheiten.

Andererseits macht es manchmal Sinn, in einer with-Abfrage selbst wiederum eine with-Klausel zu verwenden. Man ist nicht auf eine globale Spaghetti-with-Klausel beschränkt: Syntaktisch gesehen ist with ein Präfix für select. Nutze es dort, wo es die Lesbarkeit am besten unterstützt.

Spätestes jetzt sollte es klar sein, warum diese Technik „literarisches SQL“ heißt: Lesbare Abfragen zu schreiben ist eine Kunst, keine Wissenschaft.

Performanceaspekte

Bei manchen Datenbanken – insbesondere PostgreSQL – kann die Verwendung der with-Klausel die Performance beeinflussen. Siehe WITH-Klausel: Performance Auswirkungen.

Kompatibilität

BigQueryaDb2 (LUW)MariaDBaMySQLOracle DBPostgreSQLSQL ServeraSQLitewith auf oberster Ebenewith in Unterabfragen
  1. Es scheint, als können CTEs in Unterabfragen globale CTEs nicht sehen

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»

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