Zum Inhalt springen

Lambda-Funktionen

DuckDB-Lambda-Funktionen (auch „Lambdas“ oder „Lambda-Ausdrücke“) sind Ausdrücke, die eine anonyme Inline-Funktion definieren. Lambdas werden als Argument an bestimmte Listenfunktionen übergeben, die den übergebenen Lambda-Ausdruck auf ihre Elemente anwenden. Der aus der Auswertung des Lambdas resultierende Wert wird anschließend von der Listenfunktion weiterverarbeitet, um den Rückgabewert zu erzeugen.

Lambdas können auch in der COLUMNS-Klausel verwendet werden. In diesem Kontext wirkt die Lambda-Funktion als Filter: wertet sie zu true aus, bleibt die Spalte erhalten, andernfalls wird sie verworfen. Lambdas der COLUMNS-Klausel haben einen verpflichtenden Parameter, der den Spaltennamen erhält. Optional kann ein zweiter Parameter deklariert werden, der den (1-basierten) Spaltenindex erhält.

Die Syntax eines Lambda-Ausdrucks ist:

lambda ⟨parameters⟩ : ⟨expression⟩
  • ⟨parameters⟩{:.language-sql .highlight} ist eine kommagetrennte Liste von Parameternamen. Parameter dürfen beliebig benannt werden, und ihr Name darf in ⟨expression⟩{:.language-sql .highlight} referenziert werden.
  • Die Anzahl der erlaubten und erforderlichen Parameter hängt von der Listenfunktion ab, an die der Ausdruck übergeben wird.
  • Es gibt immer einen verpflichtenden Parameter, den die Listenfunktion verwendet, um das aktuelle Listenelement zu übergeben. Das ist typischerweise der erste Parameter.
  • Es gibt immer einen optionalen Parameter, den die Listenfunktion verwendet, um den (1-basierten) Index des aktuellen Elements zu übergeben. Das ist immer der letzte Parameter.
  • Der Ausdruck muss ein skalarer Ausdruck sein. Zusätzlich darf er keine Unterabfrage, Tabellenfunktion o. Ä. enthalten.
  • Der Ausdruck darf Makroaufrufe enthalten. Erlaubt sind jedoch nur skalare Makros und nur, wenn sie nicht auf einer Unterabfrage beruhen.

Die folgenden Lambda-Funktionen sind beispielsweise alle gültig:

  • lambda param : param > 1{:.language-sql .highlight}
  • lambda s : contains(concat(s, 'DB'), 'duck'){:.language-sql .highlight}
  • lambda acc, x : acc + x{:.language-sql .highlight}

Lambda-Funktionen ermöglichen den Einsatz komplexerer und flexiblerer Ausdrücke in Abfragen.

Skalare Funktionen, die Lambda-Funktionen akzeptieren

Funktion Beschreibung
apply(list, lambda(x)) Alias für list_transform.
array_apply(list, lambda(x)) Alias für list_transform.
array_filter(list, lambda(x)) Alias für list_filter.
array_reduce(list, lambda(x,y)[, initial_value]) Alias für list_reduce.
array_transform(list, lambda(x)) Alias für list_transform.
filter(list, lambda(x)) Alias für list_filter.
list_apply(list, lambda(x)) Alias für list_transform.
list_filter(list, lambda(x)) Erzeugt eine Liste aus denjenigen Elementen der Eingabe-list, für die die lambda-Funktion true zurückgibt. DuckDB muss den Rückgabetyp der lambda-Funktion nach BOOL casten können. Der Rückgabetyp von list_filter entspricht dem der Eingabeliste. Siehe list_filter-Beispiele.
list_reduce(list, lambda(x,y)[, initial_value]) Reduziert alle Elemente der Eingabe-list auf einen einzelnen skalaren Wert, indem die lambda-Funktion auf ein laufendes Ergebnis und das nächste Listenelement angewendet wird. Die lambda-Funktion hat ein optionales Argument initial_value. Siehe list_reduce-Beispiele.
list_transform(list, lambda(x)) Gibt eine Liste zurück, die das Ergebnis der Anwendung der lambda-Funktion auf jedes Element der Eingabe-list ist. Der Rückgabetyp wird durch den Rückgabetyp der lambda-Funktion bestimmt. Siehe list_transform-Beispiele.
reduce(list, lambda(x,y)[, initial_value]) Alias für list_reduce.

list_filter(list, lambda(x))

| Beschreibung | Erzeugt eine Liste aus denjenigen Elementen der Eingabe-list, für die die lambda-Funktion true zurückgibt. DuckDB muss den Rückgabetyp der lambda-Funktion nach BOOL casten können. Der Rückgabetyp von list_filter entspricht dem der Eingabeliste. Siehe list_filter-Beispiele. | | Beispiel | list_filter([3, 4, 5], lambda x : x > 4) | | Ergebnis | [5] | | Aliase | array_filter, filter |

list_reduce(list, lambda(x,y)[, initial_value])

| Beschreibung | Reduziert alle Elemente der Eingabe-list auf einen einzelnen skalaren Wert, indem die lambda-Funktion auf ein laufendes Ergebnis und das nächste Listenelement angewendet wird. Die lambda-Funktion hat ein optionales Argument initial_value. Siehe list_reduce-Beispiele. | | Beispiel | list_reduce([1, 2, 3], lambda x, y : x + y) | | Ergebnis | 6 | | Aliase | array_reduce, reduce |

list_transform(list, lambda(x))

| Beschreibung | Gibt eine Liste zurück, die das Ergebnis der Anwendung der lambda-Funktion auf jedes Element der Eingabe-list ist. Der Rückgabetyp wird durch den Rückgabetyp der lambda-Funktion bestimmt. Siehe list_transform-Beispiele. | | Beispiel | list_transform([1, 2, 3], lambda x : x + 1) | | Ergebnis | [2, 3, 4] | | Aliase | apply, array_apply, array_transform, list_apply |

Verschachtelte Lambda-Funktionen

Alle skalaren Funktionen können beliebig verschachtelt werden. Zum Beispiel verschachtelte Lambda-Funktionen, um alle Quadrate gerader Listenelemente zu erhalten:

SELECT list_transform(
list_filter([0, 1, 2, 3, 4, 5], lambda x: x % 2 = 0),
lambda y: y * y
);
[0, 4, 16]

Verschachtelte Lambda-Funktion, um jedes Element der ersten Liste zur Summe der zweiten Liste zu addieren:

SELECT list_transform(
[1, 2, 3],
lambda x :
list_reduce([4, 5, 6], lambda a, b: a + b) + x
);
[16, 17, 18]

Gültigkeitsbereich

Lambda-Funktionen folgen den Sichtbarkeitsregeln in dieser Reihenfolge:

  • innere Lambda-Parameter
  • äußere Lambda-Parameter
  • Spaltennamen
  • Makroparameter
CREATE TABLE tbl (x INTEGER);
INSERT INTO tbl VALUES (10);
SELECT list_apply(
[1, 2],
lambda x: list_apply([4], lambda x: x + tbl.x)[1] + x
)
FROM tbl;
[15, 16]

Indizes als Parameter

Alle Lambda-Funktionen akzeptieren einen optionalen Extra-Parameter, der den Index des aktuellen Elements darstellt. Das ist immer der letzte Parameter der Lambda-Funktion (z. B. i in (x, i)) und ist 1-basiert (d. h. das erste Element hat den Index 1).

Alle Elemente holen, die größer als ihr Index sind:

SELECT list_filter([1, 3, 1, 5], lambda x, i: x > i);
[3, 5]

Beispiele

list_transform-Beispiele

Jedes Listenelement um eins erhöhen:

SELECT list_transform([1, 2, NULL, 3], lambda x: x + 1);
[2, 3, NULL, 4]

Zeichenketten transformieren:

SELECT list_transform(['Duck', 'Goose', 'Sparrow'], lambda s: concat(s, 'DB'));
[DuckDB, GooseDB, SparrowDB]

Lambda-Funktionen mit anderen Funktionen kombinieren:

SELECT list_transform([5, NULL, 6], lambda x: coalesce(x, 0) + 1);
[6, 1, 7]

list_filter-Beispiele

Negative Werte herausfiltern:

SELECT list_filter([5, -6, NULL, 7], lambda x: x > 0);
[5, 7]

Durch 2 und 5 teilbar:

SELECT list_filter(
list_filter([2, 4, 3, 1, 20, 10, 3, 30], lambda x: x % 2 = 0),
lambda y: y % 5 = 0
);
[20, 10, 30]

In Kombination mit range(...) zum Erzeugen von Listen:

SELECT list_filter([1, 2, 3, 4], lambda x: x > #1) FROM range(4);
[1, 2, 3, 4]
[2, 3, 4]
[3, 4]
[4]

list_reduce-Beispiele

Summe aller Listenelemente:

SELECT list_reduce([1, 2, 3, 4], lambda acc, x: acc + x);
10

Nur Listenelemente addieren, die größer als 2 sind:

SELECT list_reduce(
list_filter([1, 2, 3, 4], lambda x: x > 2),
lambda acc, x: acc + x
);
7

Alle Listenelemente verketten:

SELECT list_reduce(['DuckDB', 'is', 'awesome'], lambda acc, x: concat(acc, ' ', x));
DuckDB is awesome

Elemente mit dem Index ohne Startwert verketten:

SELECT list_reduce(
['a', 'b', 'c', 'd'],
lambda x, y, i: x || ' - ' || CAST(i AS VARCHAR) || ' - ' || y
);
a - 2 - b - 3 - c - 4 - d

Elemente mit dem Index mit Startwert verketten:

SELECT list_reduce(
['a', 'b', 'c', 'd'],
lambda x, y, i: x || ' - ' || CAST(i AS VARCHAR) || ' - ' || y, 'INITIAL'
);
INITIAL - 1 - a - 2 - b - 3 - c - 4 - d

Einschränkungen

  • Unterabfragen in Lambda-Ausdrücken werden derzeit nicht unterstützt. Zum Beispiel:

    SELECT list_apply([1, 2, 3], lambda x: (SELECT 42) + x);
    Terminal window
    Binder Error:
    subqueries in lambda expressions are not supported
  1. Der Ausdruck kann Makroaufrufe enthalten, aber nur, wenn das Makro ein skalares Makro ist. Zusätzlich darf das Makro keine Unterabfrage enthalten und nicht auf einem anderen Makro beruhen, das eine Unterabfrage enthält.
  2. Lambda-Funktionen müssen inline als Argument der Listenfunktion definiert werden. Sie können keine Lambda-Funktion aus einem Makro zurückgeben (Sie können aber ein Makro im Ausdruck des Lambdas aufrufen).

Veraltete Syntax

Deprecated DuckDB v1.3 hat die alte Lambda-Syntax mit einfachem Pfeil (x -> x + 1) zugunsten der Python-artigen Syntax (lambda x : x + 1) als veraltet markiert.

DuckDB v1.3 führt außerdem eine neue Einstellung ein, um die Lambda-Syntax zu konfigurieren.

SET lambda_syntax = 'DEFAULT';
SET lambda_syntax = 'ENABLE_SINGLE_ARROW';
SET lambda_syntax = 'DISABLE_SINGLE_ARROW';

Derzeit aktiviert DEFAULT beide Syntaxstile, d. h. die alte Syntax mit einfachem Pfeil und die Python-artige Syntax.

DuckDB v1.5 ist die letzte Version, die die Syntax mit einfachem Pfeil ohne explizites Aktivieren unterstützt.

DuckDB v2.0 deaktiviert die Syntax mit einfachem Pfeil standardmäßig.

DuckDB v2.1 entfernt das Flag lambda_syntax und markiert die Syntax mit einfachem Pfeil vollständig als veraltet, sodass das alte Verhalten nicht mehr möglich sein wird.