Zum Inhalt springen

Typumwandlung

Typecasting ist eine Operation, die einen Wert eines bestimmten Datentyps in den nächstentsprechenden Wert eines anderen Datentyps umwandelt. Wie andere SQL-Engines unterstützt DuckDB sowohl implizites als auch explizites Typecasting.

Explizites Casten

Explizites Typecasting erfolgt mit einem CAST-Ausdruck. Beispielsweise casten CAST(col AS VARCHAR) oder col::VARCHAR die Spalte col explizit nach VARCHAR. Weitere Informationen finden Sie auf der Cast-Seite.

Implizites Casten

In vielen Situationen fügt das System Casts von selbst hinzu. Das heißt implizites Casten und geschieht beispielsweise, wenn eine Funktion mit einem Argument aufgerufen wird, das nicht zum Typ der Funktion passt, aber in den erforderlichen Typ gecastet werden kann.

Implizite Casts können nur für eine Reihe von Typkombinationen hinzugefügt werden und sind im Allgemeinen nur möglich, wenn der Cast nicht fehlschlagen kann. Ein impliziter Cast kann beispielsweise von INTEGER nach DOUBLE hinzugefügt werden – aber nicht von DOUBLE nach INTEGER.

Betrachten Sie die Funktion sin(DOUBLE). Diese Funktion nimmt als Eingabeargument eine Spalte vom Typ DOUBLE, kann aber auch mit einem Integer aufgerufen werden: sin(1). Der Integer wird in ein Double umgewandelt, bevor er an die Funktion sin übergeben wird.

Tipp Um zu prüfen, ob ein Typ implizit in einen anderen Typ gecastet werden kann, verwenden Sie die Funktion can_cast_implicitly.

Kombinations-Casting

Wenn Werte unterschiedlicher Typen zu einem unspezifizierten gemeinsamen Elterntyp kombiniert werden müssen, führt das System implizite Casts auf einen automatisch gewählten Elterntyp durch. list_value(1::INT64, 1::UINT64) erzeugt beispielsweise eine Liste vom Typ INT128[]. Die impliziten Casts in dieser Situation sind manchmal großzügiger als reguläre implizite Casts. Ein BOOL-Wert kann beispielsweise nach INT gecastet werden (wobei true auf 1 und false auf 0 abgebildet wird), obwohl das für reguläre implizite Casts nicht möglich ist.

Dieses Kombinations-Casting tritt bei Vergleichen (= / < / >), Mengenoperationen (UNION / EXCEPT / INTERSECT) und Konstruktoren verschachtelter Typen (list_value / [...] / MAP) auf.

Matrix der Cast-Operationen

Werte eines bestimmten Datentyps können nicht immer in einen beliebigen Zieldatentyp gecastet werden. Die einzige Ausnahme ist der NULL-Wert – der immer zwischen Typen umgewandelt werden kann. Die folgende Matrix beschreibt, welche Umwandlungen unterstützt werden. Wenn implizites Casten erlaubt ist, impliziert das, dass auch explizites Casten möglich ist.

Typecasting-Matrix

Auch wenn eine Cast-Operation anhand von Quell- und Zieldatentyp unterstützt wird, bedeutet das nicht unbedingt, dass die Cast-Operation zur Laufzeit erfolgreich ist.

Veraltet Vor Version 0.10.0 erlaubte DuckDB, dass jeder Typ beim Binden von Funktionen implizit nach VARCHAR gecastet werden konnte. Version 0.10.0 führte eine Breaking Change ein, die implizite Casts nach VARCHAR nicht mehr erlaubt. Die Konfigurationsoption old_implicit_casting kann verwendet werden, um zum alten Verhalten zurückzukehren. Beachten Sie jedoch, dass dieses Flag in Zukunft als veraltet markiert wird.

Verlustbehaftete Casts

Cast-Operationen, die zu einem Genauigkeitsverlust führen, sind erlaubt. Es ist beispielsweise möglich, einen numerischen Typ mit Nachkommastellen – etwa DECIMAL, FLOAT oder DOUBLE – explizit in einen ganzzahligen Typ wie INTEGER oder BIGINT zu casten. Die Zahl wird gerundet.

SELECT CAST(3.1 AS INTEGER); -- 3
SELECT CAST(3.5 AS INTEGER); -- 4
SELECT CAST(-1.7 AS INTEGER); -- -2

Die geltenden Rundungsregeln finden Sie auf der Seite zum NUMERIC-Typ.

Überläufe

Cast-Operationen, die zu einem Werteüberlauf führen würden, werfen einen Fehler. Der Wert 999 ist beispielsweise zu groß, um durch den Datentyp TINYINT dargestellt zu werden. Daher führt der Versuch, diesen Wert in diesen Typ zu casten, zu einem Laufzeitfehler:

SELECT CAST(999 AS TINYINT);
Terminal window
Conversion Error:
Type INT32 with value 999 can't be cast because the value is out of range for the destination type INT8

Obwohl die Cast-Operation von INTEGER nach TINYINT also unterstützt wird, ist sie für diesen bestimmten Wert nicht möglich. TRY_CAST kann verwendet werden, um den Wert in NULL umzuwandeln, statt einen Fehler zu werfen.

Varchar

Der Typ VARCHAR fungiert als universelles Ziel: Jeder beliebige Wert jedes beliebigen Typs kann immer in den Typ VARCHAR gecastet werden. Dieser Typ wird auch zur Anzeige von Werten in der Shell verwendet.

SELECT CAST(42.5 AS VARCHAR);

Das Casten von VARCHAR in einen anderen Datentyp wird unterstützt, kann aber zur Laufzeit einen Fehler auslösen, wenn DuckDB den bereitgestellten Text nicht parsen und in den Zieldatentyp umwandeln kann.

SELECT CAST('NotANumber' AS INTEGER);

Im Allgemeinen ist das Casten nach VARCHAR eine verlustfreie Operation, und jeder Typ kann nach der Umwandlung in Text wieder in den ursprünglichen Typ zurückgecastet werden.

SELECT CAST(CAST([1, 2, 3] AS VARCHAR) AS INTEGER[]);

Literal-Typen

Integer-Literale (wie 42) und String-Literale (wie 'string') haben besondere Regeln für implizites Casten. Weitere Informationen finden Sie auf der Seite Literal-Typen.

Listen / Arrays

Listen können explizit in andere Listen nach denselben Cast-Regeln gecastet werden. Der Cast wird auf die Kinder der Liste angewendet. Wenn wir beispielsweise eine INTEGER[]-Liste in eine VARCHAR[]-Liste umwandeln, werden die Kind-INTEGER-Elemente einzeln nach VARCHAR gecastet und eine neue Liste konstruiert.

SELECT CAST([1, 2, 3] AS VARCHAR[]);

Arrays

Arrays folgen denselben Cast-Regeln wie Listen. Zusätzlich können Arrays implizit in Listen desselben Typs gecastet werden. Ein INTEGER[3]-Array kann beispielsweise implizit in eine INTEGER[]-Liste gecastet werden.

Structs

Structs können in andere Structs gecastet werden, solange sie mindestens ein Feld gemeinsam haben.

Der Grund für diese Anforderung ist, unbeabsichtigte Fehler zu vermeiden. Haben zwei Structs keine gemeinsamen Felder, war der Cast wahrscheinlich nicht beabsichtigt.

SELECT CAST({'a': 42} AS STRUCT(a VARCHAR));

Felder, die im Ziel-Struct existieren, aber nicht im Quell-Struct, werden standardmäßig NULL.

SELECT CAST({'a': 42} AS STRUCT(a VARCHAR, b VARCHAR));

Felder, die nur im Quell-Struct existieren, werden ignoriert.

SELECT CAST({'a': 42, 'b': 43} AS STRUCT(a VARCHAR));

Die Namen des Structs können auch in einer anderen Reihenfolge stehen. Die Felder des Structs werden anhand der Namen der Structs umgeordnet.

SELECT CAST({'a': 42, 'b': 84} AS STRUCT(b VARCHAR, a VARCHAR));

Beim Kombinations-Casting sind die Felder des resultierenden Structs die Obermenge aller Felder der Eingabe-Structs. Diese Logik gilt rekursiv auch für potenziell verschachtelte Structs.

SELECT {'outer1': {'inner1': 42, 'inner2': 42}} AS c
UNION
SELECT {'outer1': {'inner2': 'hello', 'inner3': 'world'}, 'outer2': '100'} AS c;
SELECT [{'a': 42}, {'b': 84}];

Unions

Die Cast-Regeln für Unions finden Sie auf der Seite zum UNION-Typ.