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 Vorkomma-Stelle 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.- Komma als Dezimaltrennzeichen, leerer String und wissenschaftliche Notation als Text ergeben jeweils
NULL. Das sichere Konvertierungs-Pattern arbeitet zweistufig (text → float → decimal). - Postgres-Pendant ist
numeric(p, s)oderdecimal(p, s)(echte Synonyme);pdarf bis 1000 gehen (vs. 38 in SQL Server).
Voraussetzung: SQL Server 2017+ (TRIM im sicheren Pattern; vor 2017 LTRIM(RTRIM(…))-Fallback). Postgres 12+ für die Brücke.
Inhalt
- Decimal und Numeric — funktionell identisch
- Precision und Scale wählen
- Rundung vs. Vorkomma-Overflow
- Text
- Kein Text
- 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 implementieren denselben SQL-Standard, akzeptieren dieselben Parameter und teilen sich das gleiche Speicher-Layout. Sie sind funktionell identisch — eine Spalte vom Typ decimal(10, 2) und eine vom Typ numeric(10, 2) verhalten sich in Konvertierung, Arithmetik und Speicher 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.
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-Pendant mit wählbarer Skala (vgl. TRY_CONVERT für money und smallmoney) |
decimal(38, 10) | (Max-Form, 28 Vorkomma- + 10 Nachkomma-Stellen) | (Max-Form, 28 Vorkomma- + 10 Nachkomma-Stellen) | finanzmathematische / wissenschaftliche Werte |
Faustregel: Anzahl Vorkomma-Stellen + Anzahl Nachkomma-Stellen ≤ p. Wenn ein Wert mehr Vorkommastellen hat als p − s zulässt, ist die Konvertierung nicht möglich — das Ergebnis ist NULL. Nachkomma-Stellen werden hingegen still gerundet, ohne Fehler.
Rundung vs. Vorkomma-Overflow
Die Asymmetrie zwischen Nachkomma und Vorkomma ist der zentrale Hebel 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). 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).
Take-Away: Eine TRY_CONVERT(decimal(p, s), …)-Konvertierung kann den nominalen Wert stillschweigend ändern (Nachkomma-Rundung) oder ihn stillschweigend verwerfen (Vorkomma-Overflow → NULL). 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
Wird ein Wert vom Typ nvarchar/varchar an TRY_CONVERT übergeben, muss der Eingangswert eine Zahl darstellen. Als Dezimaltrennzeichen wird ausschließlich der Punkt erwartet. Tausendertrennzeichen sind nicht zulässig. Eine leere Zeichenfolge oder ein reiner Whitespace-String 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
Im Detail:
- Zeile 3:
'123,456'mit Komma ergibtNULL— das Komma wird nicht als Dezimaltrennzeichen erkannt. Anders als bei TRY_CONVERT für money und smallmoney, wo Kommas ignoriert werden. - Zeilen 5, 6: leere Zeichenfolge und reiner Whitespace 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 = 3Vorkomma-Stellen) →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).
Kein Text
Wird die Zahl bereits typisiert übergeben (int, float, decimal), kann TRY_CONVERT jeden numerischen Wert in decimal konvertieren — solange die Vorkomma-Stellen 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
Im Detail:
- Zeile 3: typisierte Dezimalzahl wird auf
sgerundet (123.456→123.46). - Zeile 4:
1234.56als typisierte Dezimalzahl (internfloat) ü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 der Hebel für das Zwei-Stufen-Pattern in der nächsten Sektion.
Sichere Typ-Konvertierung
Die Sektionen oben haben zwei Sonderfälle gezeigt, die im Import-Pfad explizit behandelt werden müssen:
- Wissenschaftliche Notation als Text (
'12345E-3') ergibtNULL. Lösung: 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:
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
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
In Multi-Engine-ETL-Pipelines stellt sich die Frage nach dem Postgres-Pendant. Die gute Nachricht: Postgres ist hier die einfachste Brücke im ganzen TRY_CONVERT-Cluster, weil numeric(p, s) und decimal(p, s) exakt dem SQL-Standard folgen.
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. pbis 1000. Postgres lässtprecisionbis 1000 zu (vs. 38 in SQL Server). Für klassische ETL-Workloads selten relevant, für Finanzmathematik mit Millionen aggregierten Werten gelegentlich nützlich. Zusätzlich kennt Postgresnumericohne Parameter — beliebige Präzision, beliebige Skala (bis zur Implementierungs-Grenze).- 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 try_cast_numeric_5_2 (p_input text)
2: RETURNS numeric(5, 2)
3: LANGUAGE plpgsql
4: IMMUTABLE
5: AS $$
6: BEGIN
7: IF p_input IS NULL OR TRIM(p_input) = '' THEN
8: RETURN NULL;
9: END IF;
10: RETURN CAST(REPLACE(p_input, ',', '.') AS numeric(5, 2));
11: EXCEPTION
12: WHEN OTHERS THEN
13: RETURN NULL;
14: END;
15: $$;
16:
17: SELECT try_cast_numeric_5_2('123,456'); -- 123.46
18: SELECT try_cast_numeric_5_2('123456E-3'); -- 123.46
19: SELECT try_cast_numeric_5_2('1234.56'); -- NULL
20: SELECT try_cast_numeric_5_2(''); -- NULL
Zusammenfassung
Zusammengefasst:
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). - 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 nicht nötig.
FAQ
decimal oder numeric — was nehmen? Beide implementieren denselben SQL-Standard und sind in SQL Server 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.
Warum gibt 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.
Rundet 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.
Wie konvertiere ich wissenschaftliche Notation ('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). Querverweis: TRY_CONVERT für float und real.
Postgres-Pendant für 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
- 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
1 Kommentar zu „Datenqualität in SQL Server // TRY_CONVERT für decimal und numeric sicher anwenden“
Die Kommentare sind geschlossen.