Zum Inhalt springen

Numerische Typen

Integer-Typen fester Breite

Die Typen TINYINT, SMALLINT, INTEGER, BIGINT und HUGEINT speichern ganze Zahlen, also Zahlen ohne Bruchanteil, in verschiedenen Bereichen. Versuche, Werte außerhalb des erlaubten Bereichs zu speichern, führen zu einem Fehler. Die Typen UTINYINT, USMALLINT, UINTEGER, UBIGINT und UHUGEINT speichern vorzeichenlose ganze Zahlen. Versuche, negative Zahlen oder Werte außerhalb des erlaubten Bereichs zu speichern, führen zu einem Fehler.

Name Aliases Min Max Größe in Bytes
TINYINT INT1 - 2^7 2^7 - 1 1
SMALLINT INT2, INT16, SHORT - 2^15 2^15 - 1 2
INTEGER INT4, INT32, INT, SIGNED - 2^31 2^31 - 1 4
BIGINT INT8, INT64, LONG - 2^63 2^63 - 1 8
HUGEINT INT128 - 2^127 2^127 - 1 16
UTINYINT UINT8 0 2^8 - 1 1
USMALLINT UINT16 0 2^16 - 1 2
UINTEGER UINT32 0 2^32 - 1 4
UBIGINT UINT64 0 2^64 - 1 8
UHUGEINT UINT128 0 2^128 - 1 16

INT8 ist ein 64-Bit-Integer und nicht das vorzeichenbehaftete Pendant zu UINT8, einem vorzeichenlosen 8-Bit-Integer. Die Typaliase INT1, INT2, INT4 und INT8 für vorzeichenbehaftete Integer stammen aus PostgreSQL, wo die Ziffern in diesen Namen die Größe in Bytes angeben, während die Typaliase für ihre vorzeichenlosen Pendants, UINT8, UINT16, UINT32 und UINT64, ihre Größe in Bits nach der C/C++-Konvention angeben.

Der Typ Integer ist die übliche Wahl, da er das beste Gleichgewicht zwischen Bereich, Speichergröße und Leistung bietet. Der Typ SMALLINT wird in der Regel nur verwendet, wenn Speicherplatz knapp ist. Die Typen BIGINT und HUGEINT sind dafür gedacht, wenn der Bereich des Integer-Typs nicht ausreicht.

Integer variabler Länge

Die zuvor genannten Integer-Typen haben gemeinsam, dass die Zahlen im Minimal- und Maximalbereich alle dieselbe Speichergröße haben: UTINYINT ist 1 Byte, SMALLINT ist 2 Bytes usw. Manchmal brauchen Sie jedoch Zahlen, die noch größer sind als das, was ein HUGEINT unterstützt! In diesen Situationen können Sie den Typ BIGNUM verwenden, der positive Zahlen ähnlich wie andere Integer-Typen speichert, aber drei zusätzliche Bytes für die benötigte Größe und ein Vorzeichenbit verwendet. Eine Zahl mit N Dezimalziffern benötigt in einem BIGNUM ungefähr 0.415 * N + 3 Bytes.

Im Gegensatz zu Implementierungen von Integern variabler Länge in anderen Systemen gibt es bei BIGNUM Grenzen: Die maximal und minimal darstellbaren Werte sind ungefähr ±4.27e20201778. Das sind Zahlen mit 20.201.779 Dezimalziffern; das Speichern einer einzelnen solchen Zahl erfordert 8 Megabyte.

Festkomma-Decimals

Der Datentyp DECIMAL(WIDTH, SCALE) (auch unter dem Alias NUMERIC(WIDTH, SCALE) verfügbar) steht für einen exakten Festkomma-Decimalwert. Beim Anlegen eines Werts vom Typ DECIMAL können WIDTH und SCALE angegeben werden, um festzulegen, welche Größe von Decimalwerten das Feld aufnehmen kann. Das Feld WIDTH bestimmt, wie viele Ziffern aufgenommen werden können, und scale bestimmt die Anzahl der Ziffern nach dem Dezimalpunkt. Der Typ DECIMAL(3, 2) kann beispielsweise den Wert 1.23 aufnehmen, aber nicht den Wert 12.3 oder den Wert 1.234. Der Standard für WIDTH und SCALE ist DECIMAL(18, 3), wenn keine angegeben werden. Wird nur WIDTH angegeben, ist SCALE standardmäßig 0DECIMAL(18) ist beispielsweise äquivalent zu DECIMAL(18, 0) und kürzt Nachkommastellen.

WIDTH und SCALE angeben

Beide Parameter sind optional, und ein nachgestelltes Komma nach WIDTH wird akzeptiert. Die folgenden Schreibweisen binden daher alle an einen konkreten Decimal-Typ:

SELECT
typeof(1.5::DECIMAL) AS "DECIMAL",
typeof(1.5::DECIMAL()) AS "DECIMAL()",
typeof(1.5::DECIMAL(10)) AS "DECIMAL(10)",
typeof(1.5::DECIMAL(10,)) AS "DECIMAL(10,)";
DECIMAL DECIMAL() DECIMAL(10) DECIMAL(10,)
DECIMAL(18,3) DECIMAL(18,3) DECIMAL(10,0) DECIMAL(10,0)

Der Alias NUMERIC akzeptiert dieselben Schreibweisen und liefert dieselben Typen.

Beachten Sie, dass ein bloßes DECIMAL kein unbeschränkter Decimal-Typ ist wie in PostgreSQL und Oracle. DuckDB bindet es immer an den konkreten Typ DECIMAL(18, 3), der auf 3 Nachkommastellen rundet und höchstens 15 Ziffern vor dem Dezimalpunkt aufnimmt.

WIDTH muss zwischen 1 und 38 liegen, und SCALE muss zwischen 0 und 38 liegen und darf WIDTH nicht überschreiten. Werte außerhalb dieser Grenzen werden vom Binder abgelehnt statt begrenzt:

SELECT 1::DECIMAL(39, 2);
Terminal window
Binder Error:
DECIMAL type width must be between 1 and 38
SELECT 1::DECIMAL(18, 20);
Terminal window
Binder Error:
DECIMAL type scale cannot be greater than width

Anders als PostgreSQL und Oracle unterstützt DuckDB kein negatives SCALE:

SELECT 1::DECIMAL(18, -1);
Terminal window
Binder Error:
DECIMAL type scale must be between 0 and 38

Arithmetik und interne Darstellung

Addition, Subtraktion und Multiplikation zweier Festkomma-Decimals liefern ein weiteres Festkomma-Decimal mit der erforderlichen WIDTH und SCALE, um das exakte Ergebnis aufzunehmen, oder werfen einen Fehler, wenn die erforderliche WIDTH die maximal unterstützte WIDTH überschreiten würde, die derzeit 38 ist.

Die Division von Festkomma-Decimals erzeugt typischerweise keine Zahlen mit endlicher Dezimalentwicklung. Daher verwendet DuckDB für alle Divisionen, an denen Festkomma-Decimals beteiligt sind, näherungsweise Gleitkommaarithmetik und liefert entsprechend Gleitkomma-Datentypen.

Intern werden Decimals je nach angegebener WIDTH als Integer dargestellt.

Breite Intern Größe (Bytes)
1-4 INT16 2
5-9 INT32 4
10-18 INT64 8
19-38 INT128 16

Die Leistung kann beeinträchtigt werden, wenn zu große Decimals verwendet werden, obwohl sie nicht benötigt werden. Insbesondere sind Decimalwerte mit einer Breite über 19 langsam, weil Arithmetik mit dem Typ INT128 deutlich teurer ist als Operationen mit den Typen INT32 oder INT64. Es wird daher empfohlen, bei einer WIDTH von 18 oder darunter zu bleiben, sofern es keinen guten Grund gibt, warum das nicht ausreicht.

Gleitkommatypen

Die Datentypen FLOAT und DOUBLE sind numerische Typen mit variabler Genauigkeit. In der Praxis sind diese Typen üblicherweise Implementierungen des IEEE-Standards 754 für binäre Gleitkommaarithmetik (einfache bzw. doppelte Genauigkeit), soweit der zugrunde liegende Prozessor, das Betriebssystem und der Compiler das unterstützen.

Name Aliases Beschreibung
FLOAT FLOAT4, REAL Gleitkommazahl einfacher Genauigkeit (4 Bytes)
DOUBLE FLOAT8 Gleitkommazahl doppelter Genauigkeit (8 Bytes)

Wie bei Festkomma-Datentypen speichert die Umwandlung aus Literalen oder Casts von anderen Datentypen in Gleitkommatypen Eingaben, die nicht exakt dargestellt werden können, als Näherungen. Es kann jedoch schwieriger vorherzusagen sein, welche Eingaben davon betroffen sind. Es überrascht beispielsweise nicht, dass 1.3::DECIMAL(1, 0) - 0.7::DECIMAL(1, 0) != 0.6::DECIMAL(1, 0), aber es kann überraschen, dass 1.3::FLOAT - 0.7::FLOAT != 0.6::FLOAT.

Außerdem sind Multiplikation, Addition und Subtraktion von Festkomma-Decimal-Datentypen exakt, während diese Operationen auf binären Gleitkomma-Datentypen nur näherungsweise sind.

Für komplexere mathematische Operationen wird intern jedoch Gleitkommaarithmetik verwendet, und präzisere Ergebnisse können erzielt werden, wenn Zwischenschritte nicht in Festkommaformate derselben Breite wie Ein- und Ausgaben gecastet werden. Beispielsweise ist (10::FLOAT / 3::FLOAT)::FLOAT * 3 = 10, während (10::DECIMAL(18, 3) / 3::DECIMAL(18, 3))::DECIMAL(18, 3) * 3 = 9.999.

Im Allgemeinen:

  • Wenn Sie die exakte Speicherung von Zahlen mit einer bekannten Anzahl von Dezimalziffern benötigen und exakte Additionen, Subtraktionen und Multiplikationen verlangen (etwa für Geldbeträge), verwenden Sie stattdessen den DECIMAL-Datentyp oder seinen Alias NUMERIC.
  • Wenn Sie schnelle oder komplizierte Berechnungen durchführen möchten, können die Gleitkomma-Datentypen besser geeignet sein. Wenn Sie die Ergebnisse jedoch für etwas Wichtiges verwenden, sollten Sie Ihre Implementierung sorgfältig auf Grenzfälle prüfen (Bereiche, Unendlichkeiten, Underflows, ungültige Operationen), die anders behandelt werden können, als Sie erwarten, und Sie sollten sich mit gängigen Gleitkomma-Fallstricken vertraut machen. Der Artikel „What Every Computer Scientist Should Know About Floating-Point Arithmetic“ von David Goldberg und die Floating-Point-Serie im Blog von Bruce Dawson bieten hervorragende Einstiegspunkte.

Auf den meisten Plattformen hat der Typ FLOAT einen Bereich von mindestens 1E-37 bis 1E+37 mit einer Genauigkeit von mindestens 6 Dezimalziffern. Der Typ DOUBLE hat typischerweise einen Bereich von etwa 1E-307 bis 1E+308 mit einer Genauigkeit von mindestens 15 Ziffern. Positive Zahlen außerhalb dieser Bereiche (und negative Zahlen außerhalb der gespiegelten Bereiche) können auf manchen Plattformen Fehler verursachen, werden aber üblicherweise in Null bzw. Unendlich umgewandelt.

Zusätzlich zu gewöhnlichen numerischen Werten haben die Gleitkommatypen mehrere Sonderwerte, die IEEE-754-Sonderwerte darstellen:

  • Infinity: Unendlich
  • -Infinity: negatives Unendlich
  • NaN: keine Zahl (not a number)

Auf Maschinen mit der erforderlichen CPU/FPU-Unterstützung folgt DuckDB der IEEE-754-Spezifikation zu diesen Sonderwerten, mit zwei Ausnahmen:

  • NaN vergleicht gleich mit NaN und größer als jede andere Gleitkommazahl.
  • Einige Gleitkommafunktionen wie sqrt / sin / asin werfen Fehler, statt NaN für Werte außerhalb ihres Definitionsbereichs zu liefern.

Um diese Werte als Literale in einem SQL-Befehl einzufügen, müssen Sie Anführungszeichen um sie setzen, Sie dürfen Infinity als Inf abkürzen, und Sie dürfen beliebige Groß-/Kleinschreibung verwenden. Zum Beispiel:

SELECT
sqrt(2) > '-inf',
'nan' > sqrt(2);
(sqrt(2) > '-inf') ('nan' > sqrt(2))
true true

Universell eindeutige Identifikatoren (UUIDs)

DuckDB unterstützt universell eindeutige Identifikatoren (UUIDs) über den Typ UUID. Diese verwenden 128 Bits und werden intern als HUGEINT-Werte dargestellt. Beim Drucken werden sie mit Kleinbuchstaben-Hexadezimalzeichen angezeigt, getrennt durch Bindestriche wie folgt: ⟨12345678⟩-⟨1234⟩-⟨1234⟩-⟨1234⟩-⟨1234567890ab⟩{:.language-sql .highlight} (insgesamt 36 Zeichen einschließlich der Bindestriche). Beispielsweise ist 4ac7a9e9-607c-4c8a-84f3-843f0191e3fd eine gültige UUID.

DuckDB unterstützt das Erzeugen von UUIDv4- und UUIDv7-Identifikatoren. Um die Version eines UUID-Werts zu ermitteln, verwenden Sie die Funktion uuid_extract_version.

UUIDv4

Um einen UUIDv4-Wert zu erzeugen, verwenden Sie die Funktion uuid() oder ihre Aliase uuidv4() und gen_random_uuid().

UUIDv7

Um einen UUIDv7-Wert zu erzeugen, verwenden Sie die Funktion uuidv7(). Um den Timestamp aus einem UUIDv7-Wert zu ermitteln, verwenden Sie die Funktion uuid_extract_timestamp:

SELECT uuid_extract_timestamp(uuidv7()) AS ts;
ts
2025-04-19 15:51:20.07+00

Rundung

Das Casten von Gleitkomma- oder Festkommatypen nach Integer bedeutet, dass die Quellzahlen gerundet werden.

Es gilt die folgende Standard-Rundungslogik:

  • Casten von FLOAT und DOUBLE nach Integer beliebiger Größe: Runden zur nächsten ganzen Zahl, bei Gleichstand (Hälften) zur nächsten geraden Zahl (Banker’s Rounding).

    SELECT 2.5::FLOAT::INTEGER AS result; -- round to even
    ┌────────┐
    │ result │
    │ int32 │
    ├────────┤
    │ 2 │
    └────────┘
  • Casten von DECIMAL nach Integer beliebiger Größe: Runden zur nächsten ganzen Zahl, bei Gleichstand (Hälften) von null weg.

    SELECT 2.5::DECIMAL::INTEGER AS result; -- round away from zero
    SELECT 2.5::INTEGER AS result; -- number literals are treated as DECIMALs
    ┌────────┐
    │ result │
    │ int32 │
    ├────────┤
    │ 3 │
    └────────┘

Wenn eine andere als die Standard-Rundungslogik erforderlich ist, sollten Funktionen wie ceil, floor, round und round_even verwendet werden.

Funktionen

Siehe Numerische Funktionen und Operatoren.