String-Funktionen im Datenbankvergleich: Concat, Substring, Trim
AI generated
SELECT
JOIN
SQL · Datenbankvergleich · Portabilitaet
String-Funktionen im Datenbankvergleich
Konkatenation, Substring und Trimmen ohne boese Ueberraschungen

Zwei Zeichenketten zusammenfuegen oder einen Teilstring extrahieren klingt nach der einfachsten Aufgabe in SQL, doch zwischen MySQL, PostgreSQL, SQL Server und Oracle unterscheiden sich Operatoren, Funktionsnamen und sogar die Zaehlweise der Zeichenposition. Wer String-Funktionen zwischen diesen Systemen portabel halten will, muss diese Unterschiede kennen, bevor Unicode und Multibyte-Zeichen zusaetzliche Fallstricke aufwerfen.

17 Min. Lesezeit MySQL · PostgreSQL · SQL Server · Oracle String-Funktionen · Unicode · Portabilitaet

1. Warum String-Funktionen zwischen Datenbanken uneinheitlich sind

Kaum ein Bereich von SQL zeigt so deutliche Unterschiede zwischen den Datenbanksystemen wie String-Funktionen. Waehrend numerische Funktionen wie SUM() oder AVG() ueber alle grossen Datenbanken hinweg fast identisch sind, haben sich fuer Textverarbeitung historisch vollstaendig unterschiedliche Namenskonventionen etabliert. Der Grund liegt in der Entstehungsgeschichte: MySQL orientierte sich an C-Bibliotheksfunktionen, PostgreSQL folgte staerker dem POSIX- und spaeter dem ANSI-Standard, SQL Server uebernahm Transact-SQL-Konventionen aus Sybase, und Oracle entwickelte PL/SQL weitgehend unabhaengig mit eigenen Namenskonventionen.

Diese Fragmentierung betrifft nicht nur Funktionsnamen, sondern auch fundamentale semantische Details wie die Zaehlweise von Zeichenpositionen, das Verhalten bei NULL-Eingaben und die Behandlung von Multibyte-Zeichen. Wer Anwendungen fuer mehrere Datenbanken schreibt oder eine Migration plant, muss diese String-Funktionen-Unterschiede im Detail kennen, da gerade Textverarbeitung in Reports, Suchfunktionen und Datenexporten extrem haeufig vorkommt und Bugs hier oft erst bei bestimmten Sonderzeichen sichtbar werden.

2. Konkatenation: der || Operator, CONCAT() und + im Vergleich

PostgreSQL und Oracle folgen dem ANSI-SQL-Standard und nutzen den Operator || fuer die Konkatenation zweier Zeichenketten, wobei beide Datenbanken bei NULL-Werten unterschiedlich reagieren: PostgreSQL gibt NULL zurueck, sobald ein Operand NULL ist, waehrend Oracle NULL in dieser Operation stillschweigend wie einen leeren String behandelt, ein haeufiger Grund fuer unterschiedliches Verhalten bei einer Migration zwischen den beiden Systemen.

MySQL unterstuetzt || nur im nicht standardmaessig aktivierten PIPES_AS_CONCAT-SQL-Modus und verwendet standardmaessig die Funktion CONCAT(a, b, ...), die beliebig viele Argumente akzeptiert und bei NULL ebenfalls NULL zurueckgibt. SQL Server verwendet historisch den +-Operator, was bei gemischten String- und Zahlentypen zu impliziten Konvertierungsfehlern fuehren kann, bietet aber seit SQL Server 2012 zusaetzlich die robustere CONCAT()-Funktion, die NULL-Werte automatisch als leeren String behandelt statt das gesamte Ergebnis auf NULL zu setzen.


-- PostgreSQL and Oracle: ANSI-standard || concatenation operator
SELECT first_name || ' ' || last_name AS full_name FROM customers;
-- PostgreSQL: NULL propagates, Oracle: NULL treated as empty string

-- MySQL: CONCAT() function, NULL in any argument makes the whole result NULL
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM customers;

-- SQL Server: legacy + operator (implicit conversion risk) vs. modern CONCAT()
SELECT first_name + ' ' + last_name AS full_name FROM customers;   -- risky with NULLs
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM customers;  -- NULL-safe

3. Teilstrings: SUBSTRING vs. SUBSTR und Index-Konventionen

Alle vier Datenbanken unterstuetzen eine Funktion zur Teilstring-Extraktion, doch der Funktionsname und die genaue Argumentreihenfolge unterscheiden sich. MySQL und SQL Server bieten SUBSTRING(string, start, length), PostgreSQL unterstuetzt sowohl SUBSTRING() als auch die kuerzere SUBSTR(), und Oracle kennt ausschliesslich SUBSTR(string, start, length) ohne die SUBSTRING-Schreibweise. Eine wichtige Gemeinsamkeit, die haeufig uebersehen wird: Alle vier Systeme zaehlen Zeichenpositionen ab 1, nicht ab 0 wie in den meisten Programmiersprachen, was bei der Portierung von Anwendungslogik in SQL ein klassischer Off-by-One-Fehler ist.

Ein feiner, aber wichtiger Unterschied betrifft negative length-Argumente und Positionen ausserhalb der Zeichenkette: MySQL und PostgreSQL geben bei einer Startposition jenseits der Stringlaenge einen leeren String zurueck, waehrend Oracles SUBSTR() mit negativen Startwerten von hinten zaehlt, ein Feature, das MySQL und PostgreSQL zwar aehnlich unterstuetzen, aber mit subtil unterschiedlichem Randfall-Verhalten bei sehr kurzen Strings.


-- MySQL and SQL Server: SUBSTRING(string, start, length)
SELECT SUBSTRING(sku, 1, 4) AS category_code FROM products;

-- PostgreSQL: supports both SUBSTRING() and the shorter SUBSTR()
SELECT SUBSTR(sku, 1, 4) AS category_code FROM products;

-- Oracle: only SUBSTR(), negative start counts from the end of the string
SELECT SUBSTR(sku, 1, 4) AS category_code FROM products;
SELECT SUBSTR(sku, -4) AS last_four_chars FROM products;

-- All four databases: character positions start at 1, not 0

4. Laenge und Trimmen: LENGTH, LEN und die TRIM-Varianten

Fuer die Stringlaenge nutzt MySQL LENGTH() fuer Bytes und CHAR_LENGTH() fuer Zeichen, ein Unterschied, der bei Multibyte-Kodierungen wie UTF-8 entscheidend ist. PostgreSQL nennt die zeichenbasierte Funktion schlicht LENGTH() und bietet OCTET_LENGTH() fuer die Byte-Laenge. Oracle verwendet ebenfalls LENGTH() fuer Zeichen, waehrend SQL Server als einzige der vier Datenbanken die abgekuerzte Funktion LEN() anstelle von LENGTH() verwendet, ein haeufiger Stolperstein beim Wechsel von einer der anderen drei Datenbanken.

Beim Trimmen von Leerzeichen oder anderen Zeichen bieten alle vier Systeme TRIM(), LTRIM() und RTRIM(), jedoch mit unterschiedlicher Syntax fuer das Entfernen spezifischer Zeichen statt reiner Leerzeichen. PostgreSQL und Oracle folgen der ANSI-Syntax TRIM(BOTH 'x' FROM string), waehrend MySQL sowohl diese Syntax als auch die kompaktere TRIM('x' FROM string) unterstuetzt. SQL Server hatte vor Version 2017 ueberhaupt kein TRIM(), sondern nur LTRIM() und RTRIM() kombiniert, was in aelteren Codebasen noch haeufig zu sehen ist.


-- MySQL: LENGTH() for bytes, CHAR_LENGTH() for characters
SELECT LENGTH(description), CHAR_LENGTH(description) FROM products;

-- PostgreSQL: LENGTH() for characters, OCTET_LENGTH() for bytes
SELECT LENGTH(description), OCTET_LENGTH(description) FROM products;

-- SQL Server: LEN() instead of LENGTH() — a common porting mistake
SELECT LEN(description) FROM products;

-- Trimming specific characters, ANSI syntax (PostgreSQL, Oracle, MySQL)
SELECT TRIM(BOTH '0' FROM sku) FROM products;

-- SQL Server before 2017: no TRIM(), combine LTRIM and RTRIM
SELECT LTRIM(RTRIM(description)) FROM products;

5. Gross- und Kleinschreibung sowie Padding-Funktionen

Die Funktionen fuer Gross- und Kleinschreibung sind eine der wenigen Ecken, in denen sich alle vier Datenbanken einig sind: UPPER() und LOWER() funktionieren identisch in MySQL, PostgreSQL, SQL Server und Oracle. Unterschiede zeigen sich jedoch bei Padding-Funktionen, die einen String auf eine bestimmte Laenge auffuellen. MySQL, PostgreSQL und Oracle bieten LPAD() und RPAD(), waehrend SQL Server keine direkten Aequivalente hat und stattdessen eine Kombination aus RIGHT(), REPLICATE() und Konkatenation benoetigt, um denselben Effekt zu erzielen.

Ein praktischer Anwendungsfall fuer Padding ist die Formatierung von Rechnungsnummern oder Artikelcodes mit fuehrenden Nullen, ein Muster, das in MySQL, PostgreSQL und Oracle mit einer einzigen LPAD()-Anweisung geloest wird, in SQL Server aber deutlich mehr Codezeilen erfordert. Wer eine Anwendung von SQL Server auf eines der anderen drei Systeme migriert, kann diese Workarounds oft erheblich vereinfachen.


-- MySQL, PostgreSQL, Oracle: LPAD() for zero-padding
SELECT LPAD(order_number, 8, '0') AS padded_order_number FROM orders;
-- Example: 42 becomes '00000042'

-- SQL Server: no native LPAD(), must combine RIGHT() and REPLICATE()
SELECT RIGHT(REPLICATE('0', 8) + CAST(order_number AS VARCHAR(8)), 8)
  AS padded_order_number
FROM orders;

-- UPPER() and LOWER() work identically on all four databases
SELECT UPPER(sku), LOWER(sku) FROM products;

6. Regulaere Ausdruecke in String-Funktionen je Datenbank

Bei regulaeren Ausdruecken zeigen sich die groessten Unterschiede zwischen den vier Datenbanken. PostgreSQL bietet mit dem Operator ~ und der Funktion regexp_replace() die vollstaendigste und am staerksten POSIX-kompatible Unterstuetzung. MySQL unterstuetzt seit Version 8.0 REGEXP_LIKE(), REGEXP_REPLACE() und REGEXP_SUBSTR() mit einer eigenen, ICU-basierten Regex-Engine, die sich in Details von PostgreSQLs POSIX-Dialekt unterscheidet.

SQL Server hatte bis vor kurzem keine native Regex-Unterstuetzung in Standard-T-SQL und benoetigte entweder CLR-Integration oder externe Funktionen, waehrend Oracle mit REGEXP_LIKE(), REGEXP_REPLACE() und REGEXP_SUBSTR() eine der PostgreSQL-Syntax aehnliche, aber nicht identische Funktionsfamilie anbietet. Wer regulaere Ausdruecke ueber mehrere Datenbanken hinweg einsetzt, sollte stets mit einfachen, portablen Mustern arbeiten und komplexe, engine-spezifische Regex-Features wie Lookahead-Assertions vermeiden, da deren Unterstuetzung stark variiert.

7. Multibyte- und Unicode-Fallstricke bei String-Funktionen

Der subtilste Fehlerbereich bei String-Funktionen zeigt sich bei Multibyte-Zeichen wie Umlauten, Emoji oder asiatischen Schriftzeichen. MySQLs Unterscheidung zwischen LENGTH() in Bytes und CHAR_LENGTH() in Zeichen wird besonders kritisch, wenn ein UTF-8-String mit deutschen Umlauten verarbeitet wird: ein einzelnes ä belegt in UTF-8 zwei Bytes, aber genau ein Zeichen, sodass LENGTH() und CHAR_LENGTH() unterschiedliche Werte liefern, waehrend ein reiner ASCII-String identische Ergebnisse zeigt und der Unterschied unbemerkt bleibt, bis die erste internationale Kundendaten importiert werden.

PostgreSQL, SQL Server und Oracle haben aehnliche Fallstricke bei Emoji, die im UTF-16-basierten NVARCHAR von SQL Server als Surrogate-Paare aus zwei 16-Bit-Einheiten kodiert werden, wodurch LEN() fuer ein einzelnes Emoji den Wert 2 statt 1 zurueckgeben kann. Bei Migrationen zwischen den Systemen sollte jede Anwendung, die auf exakte Zeichenzaehlung angewiesen ist, etwa fuer Feldlaengen-Validierung, explizit mit Testdaten pruefen, die Umlaute, Emoji und andere Multibyte-Zeichen enthalten, statt sich auf reine ASCII-Testfaelle zu verlassen.

8. Portable Wrapper-Strategien in Anwendungscode und ORMs

Fuer Anwendungen, die mehrere Datenbanken unterstuetzen muessen, lohnt sich eine eigene Abstraktionsschicht fuer die haeufigsten String-Funktionen, die je nach Zieldatenbank die passende native Syntax generiert. Die meisten ORMs wie Doctrine, Eloquent oder SQLAlchemy bieten bereits Query-Builder-Methoden fuer Konkatenation und Substring-Extraktion, die diese Unterschiede intern kapseln, sodass Anwendungscode niemals direkt CONCAT(), || oder + schreiben muss.

Fuer Faelle, in denen kein ORM zum Einsatz kommt, empfiehlt sich eine zentrale Utility-Klasse pro unterstuetzter Datenbank, die die Namensunterschiede kapselt und in automatisierten Tests explizit mit Multibyte-Testdaten gegen alle Zieldatenbanken geprueft wird. Ein haeufig uebersehener Testfall: Funktionen, die bei leeren Strings oder NULL-Eingaben unterschiedlich reagieren, sollten in der Testsuite genauso abgedeckt sein wie der Normalfall mit gefuellten Werten.


-- Portable concatenation pattern using COALESCE to guard against NULL
-- Works with the || operator on PostgreSQL and Oracle
SELECT COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') AS full_name
FROM customers;

-- Equivalent portable pattern for MySQL and SQL Server using CONCAT()
SELECT CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, ''))
  AS full_name
FROM customers;
-- Both patterns avoid NULL propagation across all four databases

9. String-Funktionen im direkten Vergleich

Die folgende Tabelle fasst die zentralen Unterschiede der besprochenen String-Funktionen zusammen.

Aufgabe MySQL PostgreSQL SQL Server / Oracle
Konkatenation CONCAT() || CONCAT() / ||
Teilstring SUBSTRING() SUBSTRING() / SUBSTR() SUBSTRING() / SUBSTR()
Laenge (Zeichen) CHAR_LENGTH() LENGTH() LEN() / LENGTH()
Padding LPAD() LPAD() Kein LPAD (SQL Server), LPAD (Oracle)

Wer haeufig zwischen SQL Server und den anderen drei Systemen migriert, sollte insbesondere Padding- und Laengenfunktionen genau pruefen, da SQL Server hier am staerksten von den anderen Datenbanken abweicht.

Mironsoft

SQL-Portabilitaet, Unicode-Audits und Datenbank-Migrationen

String-Verarbeitung, die auf jeder Zieldatenbank korrekt funktioniert?

Wir pruefen bestehende String-Funktionen auf Unicode-Fallstricke und Portabilitaetsluecken und bauen eine saubere Abstraktionsschicht fuer Konkatenation, Substring und Trimmen ueber mehrere Datenbanken hinweg.

Unicode-Audit

Pruefung von Laengen- und Substring-Funktionen mit echten Multibyte-Testdaten

Migration

Umbau von SQL-Server-spezifischen Workarounds auf portable Funktionen

Abstraktionsschicht

Zentrale Utility-Funktionen fuer Konkatenation, Substring und Trimmen

10. Zusammenfassung

Die String-Funktionen von MySQL, PostgreSQL, SQL Server und Oracle unterscheiden sich in Funktionsnamen, Operatoren und subtilen semantischen Details erheblich. Konkatenation reicht von CONCAT() ueber den ||-Operator bis zum riskanten + in SQL Server, Substring-Extraktion variiert zwischen SUBSTRING() und SUBSTR(), und selbst die scheinbar simple Laengenmessung liefert bei Multibyte-Zeichen je nach Datenbank und Funktion unterschiedliche Ergebnisse.

Wer portablen Code fuer mehrere Datenbanken schreibt, sollte diese String-Funktionen-Unterschiede hinter einer Abstraktionsschicht verbergen, konsequent mit COALESCE() gegen unerwartete NULL-Propagation absichern und Testdaten mit echten Multibyte-Zeichen statt reinem ASCII verwenden, um Unicode-Fallstricke fruehzeitig sichtbar zu machen.

String-Funktionen im Datenbankvergleich — Das Wichtigste auf einen Blick

Konkatenation

CONCAT() in MySQL, || in PostgreSQL und Oracle, + oder CONCAT() in SQL Server.

Substring

SUBSTRING() vs. SUBSTR(), alle Systeme zaehlen Positionen ab 1.

Laenge

LEN() nur in SQL Server, sonst LENGTH() oder CHAR_LENGTH() fuer Zeichen statt Bytes.

Unicode

Multibyte-Zeichen und Emoji immer explizit testen, nicht nur mit ASCII-Testdaten.

11. FAQ: String-Funktionen im Datenbankvergleich

1Warum so unterschiedlich?
Jede Datenbank entwickelte Textverarbeitung unabhaengig, orientiert an unterschiedlichen historischen Vorbildern.
2CONCAT() vs. || Operator?
Beide erreichen dasselbe, verhalten sich aber bei NULL unterschiedlich je nach Datenbank.
3Zeichenpositionen gleich gezaehlt?
Ja, alle vier Systeme zaehlen ab 1, nicht ab 0 wie die meisten Programmiersprachen.
4LENGTH() bei Umlauten in MySQL?
LENGTH() misst Bytes, nicht Zeichen. Fuer Zeichenanzahl CHAR_LENGTH() verwenden.
5Warum LEN() in SQL Server?
Historische Transact-SQL-Konvention aus der Sybase-Herkunft, haeufiger Portierungs-Stolperstein.
6LPAD() in SQL Server?
Kein natives LPAD(), muss ueber RIGHT() und REPLICATE() nachgebaut werden.
7NULL in Oracle-Konkatenation?
Oracle behandelt NULL beim || wie einen leeren String, andere Systeme geben NULL zurueck.
8Regex in allen Datenbanken?
PostgreSQL, MySQL 8.0+ und Oracle nativ, SQL Server benoetigt CLR-Integration.
9Unicode-Probleme testen?
Mit echten Umlauten und Emoji in Testdaten, nicht nur mit ASCII-Testfaellen.
10Portablen Code schreiben?
Ueber Abstraktionsschicht oder ORM, mit COALESCE() gegen NULL-Propagation abgesichert.