Zum Inhalt springen

PostgreSQL-Kompatibilität

Der SQL-Dialekt von DuckDB folgt eng den Konventionen des PostgreSQL-Dialekts. Die wenigen Ausnahmen sind auf dieser Seite aufgeführt.

Gleitkommaarithmetik

DuckDB und PostgreSQL behandeln Gleitkommaarithmetik bei Division durch Null unterschiedlich. DuckDB entspricht dem IEEE-Standard für Gleitkommaarithmetik (IEEE 754) sowohl bei Division durch Null als auch bei Operationen mit Unendlichkeitswerten. PostgreSQL gibt bei Division durch Null einen Fehler zurück, richtet sich bei Unendlichkeitswerten aber nach IEEE 754. Um die Unterschiede zu zeigen, führen Sie die folgenden SQL-Abfragen aus:

SELECT 1.0 / 0.0 AS x;
SELECT 0.0 / 0.0 AS x;
SELECT -1.0 / 0.0 AS x;
SELECT 'Infinity'::FLOAT / 'Infinity'::FLOAT AS x;
SELECT 1.0 / 'Infinity'::FLOAT AS x;
SELECT 'Infinity'::FLOAT - 'Infinity'::FLOAT AS x;
SELECT 'Infinity'::FLOAT - 1.0 AS x;
Expression PostgreSQL DuckDB IEEE 754
1.0 / 0.0 error Infinity Infinity
0.0 / 0.0 error NaN NaN
-1.0 / 0.0 error -Infinity -Infinity
‘Infinity’ / ‘Infinity’ NaN NaN NaN
1.0 / ‘Infinity’ 0.0 0.0 0.0
‘Infinity’ - ‘Infinity’ NaN NaN NaN
‘Infinity’ - 1.0 Infinity Infinity Infinity

Division von Ganzzahlen

Bei der Division von Ganzzahlen führt PostgreSQL eine Ganzzahldivision durch, DuckDB dagegen eine Gleitkommadivision:

SELECT 1 / 2 AS x;

PostgreSQL liefert 0, DuckDB liefert 0.5.

Um in DuckDB eine Ganzzahldivision durchzuführen, verwenden Sie den Operator //:

SELECT 1 // 2 AS x;

Das liefert 0.

UNION von booleschen und ganzzahligen Werten

Die folgende Abfrage schlägt in PostgreSQL fehl, wird in DuckDB jedoch erfolgreich ausgeführt:

SELECT true AS x
UNION
SELECT 2;

PostgreSQL gibt einen Fehler zurück:

Terminal window
ERROR: UNION types boolean and integer cannot be matched

DuckDB führt eine erzwungene Typumwandlung durch, führt die Abfrage daher aus und liefert Folgendes:

x
1
2

Implizite Typumwandlung bei Gleichheitsprüfungen

DuckDB führt bei Gleichheitsprüfungen implizite Typumwandlungen durch, z. B. das Umwandeln von Zeichenketten in numerische und boolesche Werte. Daher gibt es mehrere Fälle, in denen PostgreSQL einen Fehler wirft, DuckDB das Ergebnis aber erfolgreich berechnet:

Expression PostgreSQL DuckDB
‘1.1’ = 1 error true
‘1.1’ = 1.1 true true
1 = 1.1 false false
true = ‘true’ true true
true = 1 error true
‘true’ = 1 error error

Groß-/Kleinschreibung bei quotierten Bezeichnern

PostgreSQL ist unabhängig von der Groß-/Kleinschreibung. PostgreSQL erreicht das, indem unquotierte Bezeichner in SQL in Kleinbuchstaben umgewandelt werden, während Quotierung die Schreibweise erhält. Der folgende Befehl erzeugt beispielsweise eine Tabelle namens mytable, versucht aber, MyTaBLe abzufragen, weil Anführungszeichen die Schreibweise erhalten.

CREATE TABLE MyTaBLe (x INTEGER);
SELECT * FROM "MyTaBLe";
Terminal window
ERROR: relation "MyTaBLe" does not exist

PostgreSQL behandelt nicht nur quotierte Bezeichner als abhängig von der Groß-/Kleinschreibung; es behandelt alle Bezeichner so, z. B. funktioniert auch Folgendes nicht:

CREATE TABLE "PreservedCase" (x INTEGER);
SELECT * FROM PreservedCase;
Terminal window
ERROR: relation "preservedcase" does not exist

Daher funktioniert die Unabhängigkeit von der Groß-/Kleinschreibung in PostgreSQL nur, wenn Sie nie quotierte Bezeichner mit unterschiedlicher Schreibweise verwenden.

Für DuckDB war dieses Verhalten problematisch beim Zusammenspiel mit anderen Werkzeugen (z. B. Parquet, Pandas), die standardmäßig abhängig von der Groß-/Kleinschreibung sind – weil alle Bezeichner ständig in Kleinbuchstaben umgewandelt würden. Daher erreicht DuckDB Unabhängigkeit von der Groß-/Kleinschreibung, indem Bezeichner im gesamten System vollständig unabhängig von der Groß-/Kleinschreibung sind, ihre Schreibweise aber erhalten bleibt.

In DuckDB werden die Skripte oben erfolgreich ausgeführt:

CREATE TABLE MyTaBLe (x INTEGER);
SELECT * FROM "MyTaBLe";
CREATE TABLE "PreservedCase" (x INTEGER);
SELECT * FROM PreservedCase;
SELECT tbl FROM duckdb_tables();
tbl
MyTaBLe
PreservedCase

Das PostgreSQL-Verhalten, Bezeichner in Kleinbuchstaben umzuwandeln, ist über die Option preserve_identifier_case verfügbar:

SET preserve_identifier_case = false;
CREATE TABLE MyTaBLe (x INTEGER);
SELECT tbl FROM duckdb_tables();
tbl
mytable

Die unabhängige Zuordnung von Bezeichnern im System lässt sich jedoch nicht abschalten.

Doppeltes Gleichheitszeichen für Vergleiche

DuckDB unterstützt sowohl = als auch == für Gleichheitsvergleiche, PostgreSQL nur =.

SELECT 1 == 1 AS t;

DuckDB liefert true, PostgreSQL liefert:

Terminal window
postgres=# SELECT 1 == 1 AS t;
ERROR: operator does not exist: integer == integer
LINE 1: SELECT 1 == 1 AS t;

Beachten Sie, dass die Verwendung von == wegen der eingeschränkten Portabilität nicht empfohlen wird.

Vacuum von Tabellen

In PostgreSQL führt die Anweisung VACUUM eine Speicherbereinigung von Tabellen durch und analysiert sie. In DuckDB dient die Anweisung VACUUM nur dazu, Statistiken neu aufzubauen. Hinweise zur Freigabe von Speicherplatz finden Sie auf der Seite „Speicherplatz freigeben“.

Zeichenketten

Seit Version 1.3.0 maskiert DuckDB Zeichen wie ' in Zeichenketten, die in verschachtelten Datenstrukturen serialisiert werden. PostgreSQL tut das nicht.

Als Beispiel führen Sie aus:

SELECT ARRAY[''''];

PostgreSQL liefert:

{'}

DuckDB liefert:

['\'']

Funktionen

Funktion regexp_extract

Im Gegensatz zu PostgreSQLs Funktion regexp_substr liefert DuckDBs regexp_extract leere Zeichenketten statt NULLs, wenn es keine Übereinstimmung gibt.

Funktion to_date

DuckDB unterstützt die PostgreSQL-Datumsformatierungsfunktion to_date nicht. Verwenden Sie stattdessen die Funktion strptime.

Funktion date_part

Die meisten von der Funktion date_part extrahierten Bestandteile werden als Ganzzahlen zurückgegeben. Da es in DuckDB keine unendlichen Ganzzahlwerte gibt, werden für unendliche Zeitstempel NULLs zurückgegeben.

Auflösung von Typnamen im Schema

Bei CREATE TABLE-Anweisungen versucht DuckDB, Typnamen in dem Schema aufzulösen, in dem eine Tabelle angelegt wird. Zum Beispiel:

CREATE SCHEMA myschema;
CREATE TYPE myschema.mytype AS ENUM ('as', 'df');
CREATE TABLE myschema.mytable (v mytype);

PostgreSQL gibt bei der letzten Anweisung einen Fehler zurück:

Terminal window
ERROR: type "mytype" does not exist
LINE 1: CREATE TABLE myschema.mytable (v mytype);

DuckDB führt die Anweisung aus und legt die Tabelle erfolgreich an, bestätigt durch die folgende Abfrage:

DESCRIBE myschema.mytable;
column_name column_type null key default extra
v ENUM(‘as’, ‘df’) YES NULL NULL NULL

Nutzung funktionaler Abhängigkeiten für GROUP BY

PostgreSQL kann funktionale Abhängigkeiten ausnutzen, etwa i -> j in der folgenden Abfrage:

CREATE TABLE tbl (i INTEGER, j INTEGER, PRIMARY KEY (i));
SELECT j
FROM tbl
GROUP BY i;

PostgreSQL führt die Abfrage aus.

DuckDB scheitert:

Terminal window
Binder Error:
column "j" must appear in the GROUP BY clause or must be part of an aggregate function.
Either add it to the GROUP BY list, or use "ANY_VALUE(j)" if the exact value of "j" is not important.

Als Workaround fügen Sie die anderen Attribute hinzu oder verwenden Sie die Klausel GROUP BY ALL.

Verhalten der Operatoren für reguläre Ausdrücke

PostgreSQL unterstützt die POSIX-Operatoren für reguläre Ausdrücke ~ (teilweise, groß-/kleinschreibungsabhängig) und ~* (teilweise, unabhängig von der Groß-/Kleinschreibung) sowie ihre negierten Varianten !~ bzw. !~*.

In DuckDB ist ~ gleichwertig mit regexp_full_match und !~ gleichwertig mit NOT regexp_full_match. Die Operatoren ~* und !~* werden nicht unterstützt.

Die folgende Tabelle zeigt, dass die Entsprechung zwischen diesen Funktionen in PostgreSQL und DuckDB fast nicht vorhanden ist. Vermeiden Sie die POSIX-Operatoren für reguläre Ausdrücke in DuckDB.

Expression PostgreSQL DuckDB
`‘aaa’ ~ ’(a b)’` true
`‘AAA’ ~* ’(a b)’` true
`‘aaa’ !~ ’(a b)’` false
`‘AAA’ !~* ’(a b)’` false