Zeichenketten und Datumsangaben, Engine für Engine

Zeichenketten- und Datumsfunktionen unterscheiden sich zwischen Datenbanken stark in Name und Verhalten. Diese Lektion vergleicht die Syntax für dieselben Ergebnisse.

Text verbinden

1

SELECT first_name || ' ' || last_name AS customer,
       country
FROM customers
LIMIT 10;
In Planche ausführen

Ergebnis — erste 5 von 10 Zeilen

customercountry
Liam FischerES
Mateo CostaFR
Yuki JangDE
Ines MeyerAU
Leo NovakES

Öffnet Planche in einem eigenen Browser-Tab, mit geladener Beispieldatenbank und dieser Abfrage im Editor. Alle Beispiele der Seite verwenden denselben Tab weiter, und ausgeführt wird erst, wenn Sie F9 drücken.

The same expression elsewhere

-- PostgreSQL, Oracle: identical to SQLite.
SELECT first_name || ' ' || last_name AS customer FROM customers;

-- MySQL / MariaDB: || means OR unless PIPES_AS_CONCAT is set.
SELECT CONCAT(first_name, ' ', last_name) AS customer FROM customers;

-- SQL Server: + concatenates, and CONCAT() exists from 2012.
SELECT first_name + ' ' + last_name AS customer FROM customers;
SELECT CONCAT(first_name, ' ', last_name) AS customer FROM customers;

The same expression elsewhere — steht hier zum Vergleich. Die Beispieldatenbank im Browser ist SQLite, deshalb lässt sich diese Anweisung hier nicht ausführen.

Der Operator || ist der standardisierte, und PostgreSQL, Oracle und SQLite verwenden ihn. MySQL gibt || eine eigene Bedeutung – logisches ODER –, sofern der Server nicht mit PIPES_AS_CONCAT läuft; auf MySQL scheitert der Ausdruck also nicht, er liefert 0 oder 1. SQL Server verwendet +, das in die andere Richtung mehrdeutig ist: Bei zwei numerischen Spalten addiert es.

CONCAT() gibt es in MySQL, MariaDB, PostgreSQL und SQL Server (ab 2012). Damit ist es für diese vier Systeme die portabelste Form. Beim Umgang mit NULL verhält sie sich jedoch anders als die Operatoren.

Zwei Verhaltensweisen unterscheiden sich, nicht nur die Schreibweise:

  • NULL pflanzt sich durch die Operatoren fort. 'a' || NULL ist NULL in PostgreSQL und SQLite, und 'a' + NULL ist NULL in SQL Server. Ein fehlender zweiter Vorname leert also die ganze Spalte. CONCAT() behandelt NULL stattdessen als leere Zeichenkette. Oracles || ignoriert NULL ebenfalls, und zwar wegen des nächsten Punktes.
  • Oracle behandelt die leere Zeichenkette als NULL. Dort ist '' IS NULL wahr und überall sonst falsch, ein WHERE name = '', das auf MySQL Zeilen findet, findet auf Oracle keine.

Ein Datum formatieren

3

SELECT order_number,
       ordered_at,
       strftime('%Y-%m', ordered_at) AS month,
       strftime('%d/%m/%Y', ordered_at) AS day_first
FROM orders
LIMIT 10;
In Planche ausführen

Ergebnis — erste 5 von 10 Zeilen

order_numberordered_atmonthday_first
ORD-2022-0000012022-03-09 16:12:522022-0309/03/2022
ORD-2023-0000022023-12-13 00:59:502023-1213/12/2023
ORD-2024-0000032024-06-01 20:22:142024-0601/06/2024
ORD-2023-0000042023-04-12 22:22:302023-0412/04/2023
ORD-2025-0000052025-07-15 11:11:562025-0715/07/2025

Formatting a date elsewhere

-- MySQL / MariaDB
SELECT DATE_FORMAT(ordered_at, '%Y-%m') AS month FROM orders;

-- PostgreSQL, Oracle
SELECT to_char(ordered_at, 'YYYY-MM') AS month FROM orders;

-- SQL Server (2012+)
SELECT FORMAT(ordered_at, 'yyyy-MM') AS month FROM orders;
-- ...or, much faster in bulk, and the usual choice for grouping:
SELECT CONVERT(char(7), ordered_at, 126) AS month FROM orders;

Formatting a date elsewhere — steht hier zum Vergleich. Die Beispieldatenbank im Browser ist SQLite, deshalb lässt sich diese Anweisung hier nicht ausführen.

Vier verschiedene Funktionsnamen und drei verschiedene Mustersprachen. strftime verwendet das C-artige %Y-%m, DATE_FORMAT dieselben Prozentcodes mit teils anderer Bedeutung, to_char nutzt YYYY-MM, und FORMAT nutzt .NETs yyyy-MM – wo die Groß- und Kleinschreibung zählt, denn mm sind Minuten.

Zum Gruppieren statt zum Anzeigen sollten Sie eine für die jeweilige Engine günstige Form wählen. In SQL Server ist CONVERT(char(7), col, 126) über viele Zeilen deutlich schneller als FORMAT. In PostgreSQL ist date_trunc('month', col) meist günstiger als to_char und erhält zudem einen Datumswert. Beachten Sie auch die Index-Lektion: Wird die Spalte in eine Funktion eingeschlossen, kann ein Index auf dieser Spalte in der Regel nicht verwendet werden.

Planche normalisiert, was zurückkommt, egal welche Engine es erzeugt hat. Die Treiber stellen Datumsangaben als YYYY-MM-DD HH:MM:SS[.mmm] dar, damit das Raster einheitlich bleibt, und der Oracle-Treiber setzt NLS_DATE_FORMAT passend dazu, sodass ein selbst geschriebenes TO_CHAR mit dem übereinstimmt, was das Raster daneben zeigt.

Der Abstand zwischen zwei Daten

5

SELECT o.order_number,
       o.ordered_at,
       s.delivered_at,
       ROUND(julianday(s.delivered_at) - julianday(o.ordered_at), 1) AS days_to_deliver
FROM orders o
JOIN shipments s ON s.order_id = o.id
WHERE s.delivered_at IS NOT NULL
ORDER BY days_to_deliver DESC
LIMIT 15;
In Planche ausführen

Ergebnis — erste 5 von 15 Zeilen

order_numberordered_atdelivered_atdays_to_deliver
ORD-2023-0001522023-11-27 00:00:562023-12-07 22:33:0010.9
ORD-2025-0012882025-10-18 04:20:052025-10-28 19:54:5610.6
ORD-2024-0018162024-01-23 03:41:562024-02-02 18:40:5210.6
ORD-2023-0029762023-05-23 02:17:372023-06-02 15:33:5310.6
ORD-2022-0013452022-05-02 07:54:462022-05-12 19:12:5610.5

Days between two dates elsewhere

-- MySQL / MariaDB: whole days, first argument minus second.
SELECT DATEDIFF(delivered_at, ordered_at) AS days FROM ...;

-- PostgreSQL: subtracting two timestamps gives an interval.
SELECT delivered_at - ordered_at AS elapsed FROM ...;
SELECT EXTRACT(DAY FROM delivered_at - ordered_at) AS days FROM ...;

-- SQL Server: the unit comes first, and the arguments are the other way round.
SELECT DATEDIFF(day, ordered_at, delivered_at) AS days FROM ...;

-- Oracle: subtracting two DATEs gives a number of days.
SELECT delivered_at - ordered_at AS days FROM ...;

Days between two dates elsewhere — steht hier zum Vergleich. Die Beispieldatenbank im Browser ist SQLite, deshalb lässt sich diese Anweisung hier nicht ausführen.

Die Unterschiede gehen über den Namen hinaus. MySQLs DATEDIFF(a, b) nimmt zwei Argumente und liefert a - b in ganzen Tagen. SQL Servers DATEDIFF(day, a, b) nimmt zuerst die Einheit und liefert b - a. Die Argumentreihenfolge ist also umgekehrt; eine kopierte Abfrage kann deshalb ein Ergebnis mit umgekehrtem Vorzeichen liefern. PostgreSQL und Oracle verwenden die Subtraktion und liefern dabei ein Intervall beziehungsweise eine Anzahl von Tagen.

SQL Servers Variante zählt außerdem überschrittene Grenzen, nicht verstrichene Zeit: DATEDIFF(day, '2025-01-01 23:00', '2025-01-02 01:00') ergibt 1, bei zwei Stunden Abstand.

Ein NULL ersetzen

7

SELECT id,
       first_name,
       phone,
       COALESCE(phone, '(none)') AS portable,
       IFNULL(phone, '(none)')   AS sqlite_and_mysql
FROM customers
WHERE phone IS NULL
LIMIT 10;
In Planche ausführen

Ergebnis — erste 5 von 10 Zeilen

idfirst_namephoneportablesqlite_and_mysql
2MateoNULL(none)(none)
9SvenNULL(none)(none)
21LaylaNULL(none)(none)
25FreyaNULL(none)(none)
28PriyaNULL(none)(none)

Replacing a NULL elsewhere

-- Everywhere, and the one to reach for:
SELECT COALESCE(phone, '(none)') FROM customers;

-- MySQL / MariaDB / SQLite
SELECT IFNULL(phone, '(none)') FROM customers;

-- SQL Server. Note ISNULL, not IFNULL, and it takes exactly two arguments.
SELECT ISNULL(phone, '(none)') FROM customers;

-- Oracle
SELECT NVL(phone, '(none)') FROM customers;

Replacing a NULL elsewhere — steht hier zum Vergleich. Die Beispieldatenbank im Browser ist SQLite, deshalb lässt sich diese Anweisung hier nicht ausführen.

COALESCE ist standardisiert, existiert überall und nimmt beliebig viele Argumente – es liefert das erste, das nicht NULL ist. Die engine-spezifischen nehmen genau zwei, und zwei der Namen liegen nah genug beieinander, um sie zu verwechseln: MySQL und SQLite haben IFNULL, SQL Server hat ISNULL. Es gibt keinen Grund, sie in neuem Code COALESCE vorzuziehen.

Die Kurzfassung

Wenn eine Abfrage auf mehr als einer Engine laufen muss, decken CONCAT(), COALESCE() und CAST() das meiste ab. Datumsformatierung portiert nicht und ist meist in der Anwendung besser aufgehoben, wo Sie ohnehin Sprache und Zeitzone des Nutzers haben.