Wer einmal einen Preis-Import gesehen hat, der aus '123,45 €' ein NULL macht statt der erwarteten Dezimalzahl, weiß: TRY_CONVERT(decimal(5, 2), '123,45') liefert NULL, weil das Komma als Dezimaltrennzeichen nicht erlaubt ist. Und selbst wenn das Komma weg ist: TRY_CONVERT(decimal(5, 2), '1234.56') ist auch NULL — diesmal wegen einer Vorkommastelle zu viel.
Auf einen Blick:
decimal(p, s)undnumeric(p, s)sind in SQL Server funktionell identisch — der Artikel verwendetdecimal, alle Aussagen gelten 1:1 fürnumeric.TRY_CONVERTrundet Nachkommastellen still aufs, lehnt aber überzählige Vorkommastellen mitNULLab.- Bei der Text-nach-
decimal-Konvertierung ergeben Komma als Dezimaltrennzeichen, leerer String und wissenschaftliche Notation jeweilsNULL. Das Zwei-Stufen-Pattern (text → float → decimal) fängt die Notation ab — als Parsing-Workaround mit Präzisionsgrenze, nicht als Universalweg. - Postgres-Pendant ist
numeric(p, s)oderdecimal(p, s)(echte Synonyme).pdarf bis 1000 gehen (vs. 38 in SQL Server) — einTRY_CONVERT-Pendant fehlt dort allerdings, der Artikel zeigt den Wrapper.
Voraussetzung: TRY_CONVERT existiert seit SQL Server 2012. Das sichere Pattern nutzt TRIM und braucht daher SQL Server 2017+ (davor LTRIM(RTRIM(…))-Fallback). Die Postgres-Beispiele setzen keine bestimmte Version voraus.
Inhalt
- Decimal und Numeric — funktionell identisch
- Precision und Scale wählen
- Rundung vs. Vorkomma-Overflow
- Text nach decimal konvertieren
- Typisierte Zahlen nach decimal konvertieren
- Sichere Typ-Konvertierung
- Postgres-Brücke
- Zusammenfassung
- FAQ
- Verwandte Artikel
Decimal und Numeric — funktionell identisch
SQL Server stellt für die Speicherung von exakten Dezimalzahlen zwei Datentypen zur Verfügung: decimal(p, s) und numeric(p, s). Beide sind Synonyme mit denselben Precision-/Scale-Regeln und demselben Konvertierungsverhalten. Sie sind funktionell identisch — eine Spalte vom Typ decimal(10, 2) und eine vom Typ numeric(10, 2) verhalten sich in Konvertierung und Arithmetik exakt gleich.
In diesem Artikel wird durchgehend decimal verwendet. Alle Aussagen gelten 1:1 für numeric.
Precision und Scale wählen
decimal(p, s) hat zwei Parameter:
precision(p) — die Gesamtzahl der Dezimalstellen, die der Datentyp speichern kann. Erlaubt sind Werte von 1 bis 38.scale(s) — die Anzahl der Dezimalstellen rechts vom Dezimaltrennzeichen. Erlaubt sind Werte von 0 bisp.
Konkret: decimal(5, 2) speichert fünf Stellen insgesamt — drei vor und zwei nach dem Dezimaltrennzeichen. Damit ist sofort klar, warum 1234.56 scheitert und 123.456 gerundet wird.
Daraus ergibt sich der Wertebereich:
decimal(p, s) | Min | Max | Typische Verwendung |
|---|---|---|---|
decimal(5, 2) | −999,99 | +999,99 | Prozent-Sätze, kleine Preise |
decimal(10, 2) | −99 999 999,99 | +99 999 999,99 | Beträge im Buchhaltungs-Bereich |
decimal(19, 4) | −999 999 999 999 999,9999 | +999 999 999 999 999,9999 | money-ähnlich: gleiche Stellenzahl, anderer Wertebereich (vgl. TRY_CONVERT für money und smallmoney) |
decimal(38, 10) | (Max-Form, 28 Vorkomma- und 10 Nachkommastellen) | (Max-Form, 28 Vorkomma- und 10 Nachkommastellen) | finanzmathematische / wissenschaftliche Werte |
Faustregel: Anzahl Vorkommastellen + Anzahl Nachkommastellen ≤ p. Wenn ein Wert mehr Vorkommastellen hat als p − s zulässt, ist die Konvertierung nicht möglich — TRY_CONVERT liefert dann NULL, ein CAST/CONVERT löst einen Fehler aus. Nachkommastellen werden hingegen still gerundet, ohne Fehler.
Rundung vs. Vorkomma-Overflow
Die Asymmetrie zwischen Nachkomma und Vorkomma ist die zentrale Falle beim Arbeiten mit decimal:
1: SELECT TRY_CONVERT(decimal(5, 2), '123.456') -- 123.46
2: SELECT TRY_CONVERT(decimal(5, 2), '1234.56') -- NULL
3: SELECT TRY_CONVERT(decimal(5, 2), '12345.6') -- NULL
4: SELECT TRY_CONVERT(decimal(5, 2), 1234.56) -- NULL
5: SELECT TRY_CONVERT(decimal(5, 2), 123.456) -- 123.46
- Nachkomma wird auf
sStellen gerundet — kaufmännisch, die 5 rundet also vom Nullpunkt weg:10.645→10.65,-10.645→-10.65(half away from zero, kein Banker’s Rounding). Das passiert still, ohne Fehler, ohneNULL. - Vorkomma-Overflow liefert dagegen
NULL— und zwar sowohl bei Text-Input (Zeilen 2, 3) als auch bei typisierten Zahlen (Zeile 4). DasNULList dabeiTRY_CONVERT-spezifisch: EinCAST/CONVERTlöst an derselben Stelle einen Laufzeitfehler aus.
Kernaussage: Eine TRY_CONVERT(decimal(p, s), …)-Konvertierung kann den Eingabewert stillschweigend ändern (Nachkomma-Rundung) oder die Konvertierung stillschweigend mit NULL quittieren (Vorkomma-Overflow). In ETL-Pipelines ist letzteres oft die problematischere Falle: ein NULL im Ziel-Feld sieht aus wie „kein Wert geliefert“, war aber tatsächlich „Wert zu groß für die Skala“.
Text nach decimal konvertieren
Wird ein Wert vom Typ nvarchar/varchar an TRY_CONVERT übergeben, muss der Eingangswert eine Zahl darstellen. Als Dezimaltrennzeichen erwartet diese Text-nach-decimal-Konvertierung ausschließlich den Punkt. Tausendertrennzeichen sind nicht zulässig. Eine leere Zeichenfolge oder ein String nur aus Leerzeichen wird direkt zu NULL konvertiert — das ist ein wichtiger Unterschied zu float und money, wo leere Zeichenfolgen zu 0 konvertiert werden.
1: SELECT TRY_CONVERT(decimal(5, 2), NULL ) -- NULL
2: SELECT TRY_CONVERT(decimal(5, 2), N'123' ) -- 123.00
3: SELECT TRY_CONVERT(decimal(5, 2), N'123,456' ) -- NULL
4: SELECT TRY_CONVERT(decimal(5, 2), N'123.456' ) -- 123.46
5: SELECT TRY_CONVERT(decimal(5, 2), N'' ) -- NULL
6: SELECT TRY_CONVERT(decimal(5, 2), N' ' ) -- NULL
7: SELECT TRY_CONVERT(decimal(5, 2), N' 123.456' ) -- 123.46
8: SELECT TRY_CONVERT(decimal(5, 2), N'123.456 ' ) -- 123.46
9: SELECT TRY_CONVERT(decimal(5, 2), N'1234.56' ) -- NULL
10: SELECT TRY_CONVERT(decimal(5, 2), N'123456E-3') -- NULL
Die Zeilen zeigen im Einzelnen:
- Zeile 3:
'123,456'mit Komma ergibtNULL— das Komma wird nicht als Dezimaltrennzeichen erkannt. Anders als bei Datenqualität in SQL Server // TRY_CONVERT für money und smallmoney sicher anwenden, wo Kommas ignoriert werden. - Zeilen 5, 6: leere Zeichenfolge und ein String nur aus Leerzeichen werden zu
NULL. Anders als beifloat,real,moneyundsmallmoney, wo das Ergebnis0wäre. - Zeilen 7, 8: führende und folgende Leerzeichen werden abgeschnitten und verhindern die Konvertierung nicht.
- Zeile 9:
'1234.56'hat zu viele Vorkommastellen fürdecimal(5, 2)(maxp − s = 3Vorkommastellen) →NULL. - Zeile 10: wissenschaftliche Notation
'123456E-3'als Text ergibtNULL. Das ändert sich, wenn die Zahl als typisierter Wert übergeben wird (siehe nächste Sektion).
Typisierte Zahlen nach decimal konvertieren
Wird die Zahl bereits typisiert übergeben (int, float, decimal), kann TRY_CONVERT jeden numerischen Wert in decimal konvertieren — solange die Vorkommastellen passen:
1: SELECT TRY_CONVERT(decimal(5, 2), NULL ) -- NULL
2: SELECT TRY_CONVERT(decimal(5, 2), 123 ) -- 123.00
3: SELECT TRY_CONVERT(decimal(5, 2), 123.456 ) -- 123.46
4: SELECT TRY_CONVERT(decimal(5, 2), 1234.56 ) -- NULL
5: SELECT TRY_CONVERT(decimal(5, 2), 123456E-3) -- 123.46
Die Zeilen zeigen im Einzelnen:
- Zeile 3: typisierte Dezimalzahl wird auf
sgerundet (123.456→123.46). - Zeile 4: das Dezimal-Literal
1234.56— von T-SQL alsnumeric(6, 2)typisiert — überschreitetp − s = 3Vorkommastellen →NULL. - Zeile 5: wissenschaftliche Notation funktioniert als typisierte Zahl (
123456E-3→123.456→ gerundet auf123.46). Der Unterschied zur Text-Variante ist die Grundlage für das Zwei-Stufen-Pattern in der nächsten Sektion.
Sichere Typ-Konvertierung
„Sicher“ meint in dieser Serie: fehlertolerant — kein Abbruch, NULL statt Laufzeitfehler. Es meint nicht automatisch verlustfrei. Genau deshalb gehören zu diesem Pattern die Einschränkungen weiter unten.
Die Sektionen oben haben zwei Sonderfälle gezeigt, die im Import-Pfad explizit behandelt werden müssen:
- Wissenschaftliche Notation als Text (
'12345E-3') ergibtNULL. Workaround: erst zufloatkonvertieren (das toleriert die Notation), dann zudecimal(das setzt Präzision und Skala durch). - Eine leere Zeichenfolge wird vom direkten
TRY_CONVERT(decimal, …)zwar zuNULL— sobald aber das Zwei-Stufen-Pattern viafloatläuft, gilt das nicht mehr:TRY_CONVERT(float, '')ergibt0. Die leere Zeichenfolge muss daher vor demfloat-Schritt explizit aufNULLgemappt werden.
Das folgende Beispiel löst beide Sonderfälle gemeinsam — als Parsing-Workaround, nicht als Universalweg (die Einschränkungen folgen direkt unter dem Beispiel):
1: DECLARE @p_input AS nvarchar(30);
2: SET @p_input = N'123,456';
3:
4: SELECT TRY_CONVERT( decimal(5, 2)
5: , TRY_CONVERT( float
6: , REPLACE( CASE WHEN TRIM(@p_input) = ''
7: THEN NULL
8: ELSE @p_input
9: END
10: , ','
11: , '.'
12: )
13: )
14: ) AS [Output]; -- 123.46
Zwei Einschränkungen gehören zu diesem Pattern dazu:
- Eingabegrammatik. Das Pattern normalisiert ausschließlich den Dezimaltrenner (Komma → Punkt). Tausendertrennzeichen (
'1.234,56') und Währungszeichen — wie das€aus dem Eingangs-Beispiel — muss eine vorgelagerte Bereinigung entfernen, sonst bleibt das ErgebnisNULL. Auch Leerraum ist eng definiert:TRIMentfernt ohne weitere Angabe nur normale Leerzeichen, keine Tabs oder anderen Unicode-Leerraum. - Präzisionsgrenze.
float(ohne Parameterfloat(53), IEEE-754 Double Precision) ist ein Näherungsdatentyp mit 15–17 signifikanten Dezimalstellen — nicht jede Dezimalzahl ist exakt darstellbar. Für die in diesem Artikel gezeigten Werte liefert der Umweg dasselbedecimal(5, 2)-Ergebnis wie eine direkte Konvertierung. Bei Geldbeträgen und anderen fachlich exakten Werten mit mehr signifikanten Stellen kann derfloat-Zwischenschritt den Wert dagegen verändern. Wenn Exaktheit zählt und keine wissenschaftliche Notation vorkommt, ist der direkte WegTRY_CONVERT(decimal(p, s), …)ohne Zwischenschritt die bessere Wahl.
Wer das Pattern in einem ETL-Prozess in mehreren Spalten gleichzeitig braucht, abstrahiert es zu einer benutzerdefinierten Funktion fn_try_convert_decimal(@p_input nvarchar, @p_precision int, @p_scale int) — siehe Design Pattern // Sichere Typ-Konvertierung mit T-SQL.
Postgres-Brücke
Für Multi-Engine-Pipelines ist decimal die einfachste Brücke im ganzen TRY_CONVERT-Cluster: numeric(p, s) und decimal(p, s) decken in Postgres den SQL-Standard vollständig ab und erweitern ihn an einzelnen Stellen.
Drei Unterschiede gegenüber SQL Server:
- Synonyme statt nur identisch. In Postgres sind
numeric(p, s)unddecimal(p, s)echte Synonyme — die Spaltendefinition speichert intern immernumeric. In SQL Server bleibt der ursprüngliche Bezeichner erhalten. - Deklarierte
precisionbis 1000. Explizit deklariertenumeric(p, s)-Typen erlaubenpbis 1000 (vs. 38 in SQL Server). Seit Postgres 15 darf die deklariertescalesogar negativ sein (−1000 bis 1000) — sie rundet dann auf Stellen links vom Komma. Ein unbeschränktesnumericohne Parameter unterliegt deutlich größeren Implementierungsgrenzen: bis zu 131 072 Vorkommastellen und 16 383 Nachkommastellen. - Wissenschaftliche Notation als Text funktioniert. Postgres
CAST('123456E-3' AS numeric(5, 2))liefert123.46. Das Zwei-Stufen-Pattern viafloatist in Postgres also nicht nötig — die Notation wird direkt akzeptiert.
Postgres hat allerdings kein eingebautes try_cast (auch in Postgres 18, Release 2025-09-25 nicht). Ein PL/pgSQL-Wrapper liefert das NULL-statt-Exception-Verhalten:
1: CREATE OR REPLACE FUNCTION fn_try_cast_numeric_5_2
2: (
3: IN p_input text
4: )
5: RETURNS numeric(5, 2)
6: LANGUAGE plpgsql
7: IMMUTABLE
8: AS $function$
9: BEGIN
10:
11: IF p_input IS NULL OR TRIM(p_input) = '' THEN
12: RETURN NULL;
13: END IF;
14:
15: RETURN CAST(REPLACE(p_input, ',', '.') AS numeric(5, 2));
16:
17: EXCEPTION
18: WHEN invalid_text_representation OR numeric_value_out_of_range THEN
19: RETURN NULL;
20: END;
21: $function$;
22:
23: SELECT fn_try_cast_numeric_5_2('123,456'); -- 123.46
24: SELECT fn_try_cast_numeric_5_2('123456E-3'); -- 123.46
25: SELECT fn_try_cast_numeric_5_2('1234.56'); -- NULL
26: SELECT fn_try_cast_numeric_5_2(''); -- NULL
Der EXCEPTION-Block fängt gezielt die zwei erwartbaren Fehlerklassen — ungültige Zahl-Darstellung (invalid_text_representation) und Wertebereichs-Überlauf (numeric_value_out_of_range). Ein pauschales WHEN OTHERS würde auch unerwartete Fehler still zu NULL machen. Dazu ein Kosten-Hinweis: Ein Block mit EXCEPTION-Teil ist laut Postgres-Doku deutlich teurer als einer ohne. Bei großen Datenmengen und vielen erwartbaren Fehlern lohnt der Blick auf set-basierte Vorprüfungen.
Zusammenfassung
decimal(p, s)undnumeric(p, s)sind in SQL Server funktionell identisch — der Artikel verwendetdecimal, alle Aussagen gelten 1:1 fürnumeric.TRY_CONVERT(decimal(p, s), …)rundet Nachkommastellen still, lehnt aber überzählige Vorkommastellen mitNULLab. Die Asymmetrie ist die zentrale Falle in ETL-Pipelines.- Bei Text-Eingangswerten: Komma →
NULL, leere Zeichenfolge →NULL, wissenschaftliche Notation →NULL. Bei typisierten Zahlen funktioniert wissenschaftliche Notation. Daher das Zwei-Stufen-Pattern (text → float → decimal) — als Parsing-Workaround mitfloat-Präzisionsgrenze, nicht für exakte Werte mit vielen signifikanten Stellen. - Postgres-Pendant:
numeric(p, s)oderdecimal(p, s)— gleiche Wertebereiche bisp = 38, darüber hinaus bisp = 1000. Wissenschaftliche Notation als Text wird direkt akzeptiert, das Zwei-Stufen-Pattern ist dort nicht nötig.
Für die Praxis als Entscheidungshilfe:
| Eingangslage | Empfohlener Weg |
|---|---|
| Punkt-Notation, Skala bekannt | direkt TRY_CONVERT(decimal(p, s), …) |
| Komma als Dezimaltrennzeichen | Dezimaltrenner normalisieren, dann TRY_CONVERT |
| Wissenschaftliche Notation als Text | Zwei-Stufen-Pattern — nur bei akzeptablem Präzisionsrisiko |
| Geldbeträge und andere fachlich exakte Werte | kein float-Zwischenschritt — Eingabe vorab validieren |
| ETL-Fehlerdiagnose | Rohwert und konvertierten Wert getrennt speichern, Fehlerklasse protokollieren |
FAQ
decimal oder numeric — was nehmen? Beide sind in SQL Server Synonyme und funktionell identisch. Welcher Bezeichner verwendet wird, ist Konvention: decimal ist in T-SQL-Communitys häufiger anzutreffen, numeric in der ANSI-Standard-Doku. Tools wie der SSMS-Designer defaulten oft auf decimal.
TRY_CONVERT(decimal(5, 2), '123,45') NULL zurück? Weil das Komma in SQL Server nicht als Dezimaltrennzeichen erkannt wird — TRY_CONVERT erwartet ausschließlich einen Punkt. Bei deutschen Eingangsdaten muss das Komma vor der Konvertierung durch einen Punkt ersetzt werden. Das sichere Konvertierungs-Pattern oben übernimmt das mit REPLACE.
TRY_CONVERT(decimal, …) oder lehnt es ab? Beides — je nachdem, ob das Problem im Nachkomma oder im Vorkomma liegt. Nachkommastellen werden still auf s gerundet (kaufmännisch). Vorkomma-Overflow liefert NULL. Diese Asymmetrie ist in ETL-Pipelines wichtig: ein NULL im Ziel-Feld bedeutet bei decimal nicht zwangsläufig „Quelle hat keinen Wert geliefert“, sondern kann auch „Quelle hatte zu viele Vorkommastellen“ heißen.
TRY_CONVERT(decimal, …) NULL, obwohl die Zahl gültig aussieht? Meist steckt Vorkomma-Overflow dahinter: Die Zahl ist syntaktisch korrekt, hat aber mehr als p − s Vorkommastellen. Eine Gegenprobe mit größerer Precision unterscheidet die Fälle. Liefert TRY_CONVERT(decimal(38, 2), …) einen Wert, war es Overflow. Bleibt auch die Gegenprobe NULL, ist schon die Zahl-Darstellung ungültig. Für ETL-Prüfungen empfiehlt es sich, Rohwert und konvertierten Wert getrennt zu speichern und die Fehlerklasse mit zu protokollieren.
'12345E-3') sicher zu decimal? Das Zwei-Stufen-Pattern aus der Sektion „Sichere Typ-Konvertierung“ — erst zu float (das toleriert die Notation als Text), dann zu decimal (das setzt Präzision/Skala durch). Der float-Zwischenschritt ist dabei ein Parsing-Workaround: Bei mehr als rund 15 signifikanten Stellen kann er den Wert verändern (siehe die Einschränkungen in der Sektion). Querverweis: Datenqualität in SQL Server // TRY_CONVERT für float und real sicher anwenden.
TRY_CAST oder TRY_CONVERT für decimal? Beide liefern das NULL-statt-Fehler-Verhalten und sind für diesen Anwendungsfall austauschbar. TRY_CONVERT bietet zusätzlich den optionalen style-Parameter — für decimal spielt er keine Rolle, bei Datums- und Geld-Konvertierungen dagegen schon. Wer nah am SQL-Standard bleiben will, nimmt TRY_CAST. Den Vergleich aller vier Funktionen liefert Datenqualität // Grundlagen der Typ-Konvertierung mit T-SQL.
TRY_CONVERT(decimal, …)? CAST(s AS numeric(p, s)) oder CAST(s AS decimal(p, s)) — Postgres macht keinen Unterschied. Für NULL-statt-Exception-Verhalten ist ein PL/pgSQL-Wrapper nötig (Postgres hat kein eingebautes try_cast, Stand 18.0). Postgres ist außerdem liberaler bei Text-Inputs: wissenschaftliche Notation wird direkt akzeptiert.
Verwandte Artikel
ETL-Kontext:
- Datenqualität in einem ETL-Prozess
- ETL vs. ELT — woran du erkennst, welches Muster du wirklich gebaut hast — Makro-Einordnung: ETL vs. ELT als Architektur-Entscheidung, nicht als Reihenfolge der Buchstaben.
TRY_CONVERT für andere Datentypen:
- Datenqualität in SQL Server // TRY_CONVERT für date, datetime, datetime2 und time sicher anwenden
- Datenqualität in SQL Server // TRY_CONVERT für bigint, int, smallint und tinyint sicher anwenden
- Datenqualität in SQL Server // TRY_CONVERT für money und smallmoney sicher anwenden
- Datenqualität in SQL Server // TRY_CONVERT für float und real sicher anwenden
- Datenqualität in SQL Server // TRY_CONVERT für bit sicher anwenden — Ja/Nein-Werte konvertieren
Grundlagen:
- Datenqualität // Grundlagen der Typ-Konvertierung mit T-SQL — CAST, CONVERT, TRY_CAST und TRY_CONVERT im Vergleich.