2025-02-25
Präfix-Aliase in SQL
Hannes Mühleisen
Syntax
„Perhaps we should just leave nature alone, to its simple one-assed schematics.“
— Dr. Alphonse Mephesto, South Park Episode #5
In unserem geliebten SQL gibt es oft mehr als einen Weg zum Ziel. Join-Bedingungen lassen sich zum Beispiel implizit (und gefährlich) in der WHERE-Klausel definieren – oder mit der (besseren) Syntax JOIN ... ON .... Generell kann „mehr als ein Weg“ verwirrend und manchmal sogar gefährlich sein.
Gleichzeitig sind wir bei DuckDB stolz darauf, freundlicheres SQL zu bieten. Zu viele Menschen tippen das Zeug von Hand, besonders in der eher ad-hoc geprägten Analytik.
Gibt es einen guten Grund, die SQL-Syntax um etwas Nützliches zu erweitern, ziehen wir das zumindest in Betracht. Andere schauen genau hin. Unsere GROUP BY ALL-Syntax haben inzwischen fast alle SQL-Systeme übernommen (und ihre kleinen Geschwister auch).
Aliase
In SQL kann man Aliase für allerlei Dinge definieren: SELECT-Ausdrücke, Tabellennamen, Unterabfragen usw. Manchmal geht es nur um lesbare Spaltennamen im Ergebnis, manchmal muss man sich auf einen komplexen Ausdruck zum Beispiel in der ORDER BY-Klausel beziehen, ohne ihn zu wiederholen und auf den Optimizer zu hoffen. Aliase stehen hinter dem, was sie benennen, mit AS – das Wort AS selbst ist optional. Diese beiden Anweisungen sind gleichwertig:
SELECT 42 AS fortytwo;SELECT 42 fortytwo;Der Alias folgt dem Ausdruck (42), und AS ist optional. Dass der Alias hinter dem beschriebenen Ding steht, ist in der Programmierung eher ungewöhnlich: Typischerweise definiert man zuerst den Alias und dann den Ausdruck. Zum Beispiel in C:
int fortytwo = 42;Es erscheint sinnvoll, zuerst den Alias zu nennen – schließlich ist das der Name, mit dem wir später darauf verweisen. SQL zwingt uns zum Gegenteil und erhöht damit die mentale Last. Außerdem sind Aliase am Ende schwer zu finden, wenn eine Abfrage mehrere komplexe Ausdrücke enthält. Hier die ersten Zeilen der berüchtigten TPC-H-Query 1:
SELECT l_returnflag, l_linestatus, sum(l_quantity) sum_qty, sum(l_extendedprice) sum_base_price, sum(l_extendedprice * (1 - l_discount)) sum_disc_price, sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) sum_charge, avg(l_quantity) avg_qty, avg(l_extendedprice) avg_price, avg(l_discount) avg_disc, count(*) count_order ...Die Aliase sind hier schwer zu erkennen – und das ist noch kein komplexes Beispiel. Was, wenn man die Aliase in SQL voranstellen könnte? Warten Sie nicht länger.
Präfix-Aliase in DuckDB
In der aktuellen DuckDB-Version 1.2.0 haben wir still und leise eine weitere (unserer Meinung nach) nützliche Syntaxerweiterung ausgeliefert: Der Alias darf vor dem benannten Ausdruck stehen, mit Doppelpunkt-Syntax (:). Das war weniger schwierig als gedacht – „nur“ ein paar Änderungen am Bison-Parser, den wir von Postgres geerbt haben (und gerade ersetzen). Hier noch einmal das Beispiel von vorhin:
SELECT fortytwo: 42;Präfix-Aliase funktionieren auch für Tabellennamen, z. B.:
SELECT *FROM my_table: some_other_table;Aliase können bei Bedarf mit doppelten Anführungszeichen quotiert werden:
SELECT "forty two": 42;Präfix-Aliase eignen sich für so gut wie alles, zum Beispiel Ausdrücke, Funktionsaufrufe und Unterabfragen in der SELECT-Klausel:
SELECT e: 1 + 2, f: len('asdf'), s: (SELECT 42);Sie gelten auch für Funktionsaufrufe und Unterabfragen in der FROM-Klausel, z. B.:
SELECT *FROM r: range(10), v: (VALUES (42)), s: (FROM range(10))Die VALUES-Klausel und die Unterabfrage mit FROM brauchen hier zusätzliche Klammern – nötig, um den bösen Bison-Parser-Generator zu besänftigen. Schauen wir uns das Q1-Beispiel von vorhin noch einmal an, diesmal mit Präfix-Aliasen:
SELECT l_returnflag, l_linestatus, sum_qty: sum(l_quantity), sum_base_price: sum(l_extendedprice), sum_disc_price: sum(l_extendedprice * (1-l_discount)), sum_charge: sum(l_extendedprice * (1-l_discount) * (1+l_tax)), avg_qty: avg(l_quantity), avg_price: avg(l_extendedprice), avg_disc: avg(l_discount), count_order: count(*) ...Zwischen : und AS gibt es keinen semantischen Unterschied; beide führen zu denselben Query-Konstrukten.
Credits
Die Idee stammt vom Looker-Veteranen Michael Toy. Wir danken ihm für den Vorschlag. Dank auch an die Legende Lloyd Tabb, der uns Michaels Idee empfohlen hat. Sehen Sie sich außerdem Mark Needhams Video zu DuckDBs Präfix-Aliasen an.