Datenqualität in SQL Server // TRY_CONVERT für money und smallmoney sicher anwenden

Wer einmal einen Kassen-Report mit Werten wie '1.234,56 €' aus einer CSV in eine SQL-Server-Datenbank importieren musste, kennt das Muster: TRY_CONVERT(money, '1,234.56') liefert 1234.5600. Doch TRY_CONVERT(money, '1.234,56') liefert NULL. Und selbst wenn der Import sauber läuft: money / 100 * 100 ist nicht zwangsläufig dasselbe wie der Ausgangswert.

Auf einen Blick:

  • money (±922 337 203 685 477, 8 Byte) und smallmoney (±214 748,3647, 4 Byte) speichern fest vier Nachkommastellen — ihr Wertebereich lässt sich vollständig mit decimal(19, 4) beziehungsweise decimal(10, 4) abbilden.
  • Der Rundungs-Pitfall: money / 100 * 100 ist nicht zwangsläufig der Ausgangswert, denn jedes Zwischen-Ergebnis rundet implizit auf vier Nachkommastellen. Für mehrstufige Arithmetik ist decimal(p, s) die bessere Wahl.
  • Bei Text-Eingaben ignoriert TRY_CONVERT das Komma (aus '123,45' wird 12345.00), und die leere Zeichenfolge wird zu 0.00. Das sichere Pattern behandelt beide Fälle.
  • In Postgres ist numeric(19, 4) das portable Pendant — der Postgres-eigene money-Typ hängt am Session-Locale lc_monetary. Ein direktes Try-Pendant fehlt, der Artikel zeigt den PL/pgSQL-Wrapper fn_try_cast_numeric_19_4.

Voraussetzung: TRY_CONVERT gibt es seit SQL Server 2012. Das sichere Pattern verwendet zusätzlich TRIM und braucht damit SQL Server 2017+ (davor LTRIM(RTRIM(…))). Alle Beispiele arbeiten mit Inline-Literalen ohne Sample-Datenbank. Die Postgres-Seite setzt keine bestimmte Version voraus, nur der pg_input_is_valid-Hinweis braucht Postgres 16 oder neuer.

Inhalt

Wertebereich und Speicherbedarf

SQL Server stellt für die Speicherung von Währungswerten zwei Datentypen zur Verfügung. Beide haben fest vier Nachkommastellen. Ihr Wertebereich lässt sich vollständig mit einem decimal(p, 4) passender Gesamt-Stellenzahl abbilden. Trotzdem sind money und decimal nicht dasselbe: Speicherung und Verhalten in Berechnungen unterscheiden sich (siehe Rundungs-Pitfall).

TypMinMaxBytesNachkommastellendecimal-Abbildung
money−922 337 203 685 477,5808+922 337 203 685 477,580784decimal(19, 4)
smallmoney−214 748,3648+214 748,364744decimal(10, 4)

Praktische Konsequenz für die Typ-Wahl: smallmoney ist nur dort sinnvoll, wo der Wertebereich sicher unter ±214 748 bleibt (Speicher-Halbierung, 4 statt 8 Byte). Wird der smallmoney-Wertebereich nicht garantiert eingehalten, ist money die größere der beiden Währungsvarianten. Für neue Modelle, deren Werte in Berechnungen einfließen, lohnt vorab die Prüfung, ob nicht ohnehin decimal(p, s) passt (nächster Abschnitt).

Rundungs-Pitfall — money vs. decimal

Die Datentypen money und smallmoney weisen eine Besonderheit bei mehrstufigen Berechnungen auf: Bei money / 100 bleibt der Ergebnistyp money (gegenüber int hat money die höhere Typ-Präzedenz), und damit steht dem Zwischen-Ergebnis nur die feste Skala von vier Nachkommastellen zur Verfügung. Der Rundungsverlust eines Teilschritts geht so in den nächsten ein. Bei decimal(p, s) bestimmt SQL Server Precision und Skala des Ergebnisses nach eigenen Regeln — in der Division wächst zunächst die Skala. Erst die Precision-Obergrenze 38 kann auch dort Rundung erzwingen (siehe unten).

  1: SELECT CAST(123.45678 AS money) AS [Output];                    -- 123.4568
  2: SELECT CAST(123.45678 AS money) / 100         AS [Output];      -- 1.2345  (Verlust ab hier)
  3: SELECT CAST(123.45678 AS money) / 100 * 100   AS [Output];      -- 123.4500 (nicht gleich 123.4568)

  1: SELECT CAST(123.45678 AS decimal(10, 4)) AS [Output];                   -- 123.4568
  2: SELECT CAST(123.45678 AS decimal(10, 4)) / 100         AS [Output];     -- 1.23456800
  3: SELECT CAST(123.45678 AS decimal(10, 4)) / 100 * 100   AS [Output];     -- 123.45680000

Bei der Verwendung des Datentyps money verliert das Ergebnis in der ersten Division an Genauigkeit. Der Wert aus Zeile 3 ist nicht mehr identisch mit dem Ausgangswert aus Zeile 1. Bei decimal(10, 4) liefert dieselbe Berechnung den Ausgangswert vollständig zurück — in diesem Beispiel. Bei komplexeren Ausdrücken können die Precision-/Scale-Regeln von SQL Server (Obergrenze 38) auch bei decimal zu Rundung führen.

Kernaussage: Bei mehrstufigen Reporting-Berechnungen (Brutto/Netto, Steuer-Aufrechnungen, Allokations-Schlüssel) akkumuliert die implizite money-Zwischen-Rundung Fehler. Wer money nur für die Speicher-Spalten verwendet und für die Arithmetik auf decimal(p, s) ausweicht, vermeidet das — siehe auch Datenqualität in SQL Server // TRY_CONVERT für decimal und numeric sicher anwenden.

Text nach money konvertieren

Text-Eingangswerte kommen typischerweise aus CSV-Importen mit Betrags-Spalten. Wird ein solcher nvarchar-/varchar-Wert an TRY_CONVERT übergeben, erwartet die Konvertierung den Punkt als einziges Dezimaltrennzeichen. Ein Komma im Text wird nicht als Dezimaltrennzeichen interpretiert, sondern wie ein Gruppierungszeichen ignoriert, und mehr als vier Nachkommastellen rundet die Konvertierung auf die vierte. Die leere Zeichenfolge wird zu 0.00 konvertiert. Das ist ein wichtiger Unterschied zum decimal-Ziel: TRY_CONVERT(decimal(19, 4), N'') liefert NULL.

  1: SELECT TRY_CONVERT(money, NULL          ) -- NULL
  2: SELECT TRY_CONVERT(money, N'12345678'   ) -- 12345678.00
  3: SELECT TRY_CONVERT(money, N'123,45678'  ) -- 12345678.00
  4: SELECT TRY_CONVERT(money, N'123.45678'  ) -- 123.4568
  5: SELECT TRY_CONVERT(money, N''           ) -- 0.00
  6: SELECT TRY_CONVERT(money, N' '          ) -- 0.00
  7: SELECT TRY_CONVERT(money, N'  123.45678') -- 123.4568
  8: SELECT TRY_CONVERT(money, N'123.45678  ') -- 123.4568
  9: SELECT TRY_CONVERT(money, N'12345678E-3') -- NULL
 10: SELECT TRY_CONVERT(money, N'1,234.5678' ) -- 1234.5678
 11: SELECT TRY_CONVERT(money, N'1.234.5678' ) -- NULL
 12: SELECT TRY_CONVERT(money, N'1,2,3,4'    ) -- 1234.00
 13: SELECT TRY_CONVERT(money, N'1,2,3.4'    ) -- 123.40
 14: SELECT TRY_CONVERT(money, N'1,2.3.4'    ) -- NULL
 15: SELECT TRY_CONVERT(money, N'1,2.3,4'    ) -- 12.34

Die Zeilen zeigen im Einzelnen:

  • Zeile 2: Eine reine Ziffernfolge konvertiert wie erwartet.
  • Zeile 3: Das Komma wird nicht als Dezimaltrennzeichen interpretiert, sondern ignoriert: Aus '123,45678' wird 12345678.00 — ein fachlich falscher Wert, ganz ohne Fehlersignal.
  • Zeile 4: Der Punkt wirkt als Dezimaltrennzeichen, die fünfte Nachkommastelle wird auf die vierte gerundet.
  • Zeilen 5, 6: Eine leere Zeichenfolge und ein String nur aus Leerzeichen werden zu 0.00 konvertiert, nicht zu NULL.
  • Zeilen 7, 8: Führende und folgende Leerzeichen sind erlaubt und ändern das Ergebnis nicht.
  • Zeile 9: Wissenschaftliche Notation wird als Text nicht akzeptiert. Als typisierte Zahl funktioniert sie (nächste Sektion). Wie das Pattern damit umgeht, steht in dessen Einschränkungen.
  • Zeilen 10–15: Die Kombinations-Fälle zeigen beobachtetes Verhalten, keine dokumentierte Parser-Grammatik: In den getesteten Eingaben wirkt ein einzelner Punkt als Dezimaltrennzeichen, Kommas werden als Gruppierungszeichen ignoriert, ab dem zweiten Punkt liefert die Konvertierung NULL. Als Validierung deutscher Zahlennotation taugt dieses Verhalten ausdrücklich nicht.

Kernaussage: Für ETL-Prozesse ist die kritischste Eigenheit dieser Konvertierung nicht das NULL, sondern der stille Falschwert: Das geschluckte Komma macht aus '123,45' ein 12345.00, ohne Fehler und ohne Warnung. Zusammen mit der leeren Zeichenfolge, die zu 0.00 wird, sind das die zwei Fälle, die das Pattern in „Sichere Typ-Konvertierung“ vorab behandelt.

Typisierte Zahlen nach money konvertieren

Kommt der Eingangswert bereits typisiert an (intfloatdecimal), konvertiert TRY_CONVERT jeden numerischen Wert nach money, solange er in den Wertebereich passt. Werte mit mehr als vier Nachkommastellen werden auf die vierte gerundet — der Wert kann sich also schon bei der Konvertierung ändern.

  1: SELECT TRY_CONVERT(money, NULL       ) -- NULL
  2: SELECT TRY_CONVERT(money, 12345678   ) -- 12345678.00
  3: SELECT TRY_CONVERT(money, 123,45678  ) -- 123.00
  4: SELECT TRY_CONVERT(money, 123.45678  ) -- 123.4568
  5: SELECT TRY_CONVERT(money, 12345678E-5) -- 123.4568

Die Zeilen zeigen im Einzelnen:

  • Zeile 3: 123,45678 ist keine Dezimalzahl. Das Komma trennt hier Funktions-Argumente: TRY_CONVERT erhält die Ganzzahl 123 als Eingangswert und 45678 als style-Parameter, der für money wirkungslos ist.
  • Zeile 4: Das Dezimal-Literal 123.45678 (von T-SQL als numeric(8, 5) typisiert) wird auf die vierte Nachkommastelle gerundet.
  • Zeile 5: 12345678E-5 ist ein float-Literal (E-Notation erzeugt float) und wird ebenfalls zu 123.4568 gerundet. Als Text (Zeile 9 der vorigen Sektion) ergibt dieselbe Notation NULL.

Anders als bei den Integer-Zielen, die Nachkommastellen abschneiden (siehe Datenqualität in SQL Server // TRY_CONVERT für bigint, int, smallint und tinyint sicher anwenden), rundet die Konvertierung nach money. Für smallmoney greift zusätzlich der engere Wertebereich: Werte außerhalb ±214 748,3647 quittiert TRY_CONVERT mit NULL, wo CONVERT einen Laufzeitfehler auslöst.

Sichere Typ-Konvertierung

„Sicher“ meint in dieser Serie fehlertolerant: kein Abbruch, NULL statt Laufzeitfehler. Semantisch korrekt ist damit noch nichts garantiert — gerade bei money liefert eine „erfolgreiche“ Konvertierung mitunter einen falschen Wert, weil das ignorierte Komma aus '123,45' still 12345.00 macht. Das Pattern unten beseitigt genau die zwei beschriebenen stillen Fehlkonvertierungen. Es validiert nicht die vollständige Eingabegrammatik: Normalisieren ist kein Validieren.

Zwei Sonderfälle aus den Sektionen oben brauchen im Import-Pfad eine explizite Behandlung:

  • Leere Zeichenfolge → 0.00: Wenn das fachlich falsch ist (der Regelfall bei CSV-Importen), muss die leere Zeichenfolge vor dem TRY_CONVERT auf NULL gemappt werden.
  • Dezimal-Komma → ignoriert: Liefert die Quelle deutsche Notation, muss das Komma vor der Konvertierung durch einen Punkt ersetzt werden — sonst entsteht der stille Falschwert.

Das folgende Beispiel löst beide Sonderfälle direkt am money-Ziel, ohne Umweg über andere Typen. Es setzt voraus, dass die Quelle verlässlich deutsche Notation liefert — die Einschränkungen folgen unter dem Beispiel:

  1: DECLARE @p_input AS nvarchar(30);
  2: SET @p_input = N'123,45678';
  3: 
  4: SELECT TRY_CONVERT( money
  5:                   , REPLACE( CASE WHEN TRIM(@p_input) = ''
  6:                                      THEN NULL
  7:                                      ELSE @p_input
  8:                                 END
  9:                            , ','
 10:                            , '.'
 11:                            )
 12:                   ) AS [Output];  -- 123.4568

Zwei Einschränkungen gehören zu dem Pattern dazu:

  • Eingabegrammatik: Das Pattern normalisiert ausschließlich das Dezimal-Komma und setzt damit ein bekanntes Quell-Locale voraus. Bei US-Notation würde dieselbe Ersetzung aus '1,234' (gemeint: 1234) ein 1.234 machen — die Normalisierung selbst erzeugt dann den stillen Falschwert (siehe Entscheidungsmatrix: unbekanntes Locale → zurückweisen). Tausenderpunkte ('1.234,56') und Währungszeichen wie das  aus dem Eingangs-Beispiel muss eine vorgelagerte Bereinigung entfernen, sonst stehen nach der Komma-Ersetzung zwei Punkte im String und das Ergebnis ist NULL. Und TRIM entfernt ohne weitere Angabe nur das normale Leerzeichen (char(32)), einen String aus Tabs oder anderem Unicode-Leerraum erkennt das Pattern deshalb nicht als „leer“.
  • E-Notation bewusst außen vor: Als Text ergibt sie weiterhin NULL (Zeile 9 der Test-Matrix). Gehört sie ausdrücklich zum Eingangsschema, ist sie ein separater Fall: Ein float-Zwischenschritt (TRY_CONVERT(float, …) vor dem money-Ziel) parst sie, arbeitet aber mit 15–17 signifikanten Stellen, während money bis zu 19 trägt (15 Vorkommastellen plus 4 Nachkommastellen). Für Geldbeträge ist das eine Parsing-Notlösung mit Präzisionsrisiko und kein Default — sonst ist E-Notation besser ein Datenqualitätsfehler als ein Parsing-Fall.

Wer das Pattern in einem ETL-Prozess in mehreren Spalten gleichzeitig braucht, abstrahiert es zu einer benutzerdefinierten Funktion fn_try_convert_money(@p_input nvarchar) — siehe Design Pattern // Sichere Typ-Konvertierung mit T-SQL.

Postgres-Brücke

Postgres bietet zwei Wege, Währungswerte zu speichern — die Wahl fällt zwischen Portabilität und Locale-Komfort:

  • numeric(19, 4) — die portable Abbildung: Deckt den gesamten money-Wertebereich ab, mit derselben Skala von vier Nachkommastellen und unabhängig vom Session-Locale. Es ist die portable numerische Repräsentation, kein semantisch identischer Geld-Typ — Währung und Formatierung trägt es nicht. Die Empfehlung für ETL-Workloads.
  • money — der Locale-gebundene Postgres-Typ: Währungssymbol, Trennzeichen und Skala folgen der Session-Locale lc_monetary. Bei einer deutschen Locale (etwa de_DE.UTF-8) erwartet der Cast typischerweise '1.234,56 €', bei einer US-Locale '$1,234.56' — die exakten Formen und Locale-Namen sind system-abhängig. Für portable Workloads nicht empfohlen, weil Format-Drift zwischen Session-Locales das Verhalten fragil macht.

Ein direktes TRY_CONVERT-Pendant, das in einem Aufruf den Zielwert oder NULL liefert, fehlt auch in Postgres 18. Eingebaut ist seit Postgres 16 immerhin die fehlertolerante Validierung über pg_input_is_valid (dazu unten mehr). Der PL/pgSQL-Wrapper unten liefert das NULL-statt-Exception-Verhalten und übernimmt gleich die Komma-Normalisierung und die sichere Leere-String-Semantik des Patterns oben:

  1: CREATE OR REPLACE FUNCTION fn_try_cast_numeric_19_4
  2: (
  3:     IN    p_input              text
  4: )
  5: RETURNS numeric(19, 4)
  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(19, 4));
 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_19_4('123,45678');   -- 123.4568
 24: SELECT fn_try_cast_numeric_19_4(' 123.45 ');    -- 123.4500
 25: SELECT fn_try_cast_numeric_19_4('1.234.5678');  -- NULL
 26: SELECT fn_try_cast_numeric_19_4('');            -- NULL

Der EXCEPTION-Block fängt gezielt die zwei erwartbaren Fehlerklassen: invalid_text_representation für ungültige Darstellungen (etwa den Doppel-Punkt nach einer missglückten Normalisierung) und numeric_value_out_of_range für Overflow. Ein pauschales WHEN OTHERS würde auch unerwartete Fehler still zu NULL machen. Und der Block kostet: Laut Postgres-Doku ist ein BEGIN-Block mit EXCEPTION-Teil deutlich teurer als einer ohne. Für Massen-Imports hilft seit Postgres 16 die eingebaute Validierung: pg_input_is_valid(raw_value, 'numeric(19,4)'), auf die Staging-Spalte angewandt, prüft set-basiert die Konvertierbarkeit ohne fehlschlagenden Cast — pg_input_error_info(…) liefert bei Bedarf die Fehlerdetails. Der Wrapper bleibt das Komfort-Pattern für die Einzelwert-Konvertierung.

Wertebereich- und Skala-Mapping zwischen den Engines:

T-SQLPostgres-Abbildung (portabel)SkalaBytes (T-SQL / Postgres)
moneynumeric(19, 4)Festkomma, Skala 48 / variabel
smallmoneynumeric(10, 4)Festkomma, Skala 44 / variabel
decimal(p, s)numeric(p, s)Festkomma, Skala s5–17 / variabel

Plattform-übergreifender Hinweis: Postgres-numeric hat keine feste Skala von vier Nachkommastellen wie T-SQL-money — der spezifische money-Pitfall der Zwischen-Rundung tritt dort nicht auf, im gezeigten Beispiel bleibt der Wert vollständig erhalten. Ganz rundungsfrei ist aber auch Postgres nicht: Die Division bestimmt eine endliche Ergebnisskala (1::numeric / 3 liefert standardmäßig 20 Nachkommastellen), Rundung ist also grundsätzlich möglich. Ein unbeschränkt deklariertes numeric unterliegt sehr großen Implementierungsgrenzen (bis zu 131 072 Vorkommastellen und 16 383 Nachkommastellen). Für Cross-DB-Reporting ist das ein wichtiger Konsistenz-Anker und ein zusätzliches Argument gegen den Postgres-money-Typ.

Zusammenfassung

  • money und smallmoney speichern fest vier Nachkommastellen, ihr Wertebereich lässt sich vollständig in decimal(19, 4) beziehungsweise decimal(10, 4) abbilden. Mehrstufige Berechnungen runden jedes Zwischen-Ergebnis implizit — für Arithmetik decimal(p, s) bevorzugen.
  • Bei Text-Eingangswerten wird das Komma nicht als Dezimaltrennzeichen interpretiert, sondern ignoriert, die leere Zeichenfolge wird zu 0.00. Beides fängt das sichere Pattern ab (Komma-REPLACE plus CASE/TRIM).
  • E-Notation ergibt als Text NULL, als typisierte Zahl funktioniert sie. Das Pattern lässt sie bewusst außen vor — wer sie im Eingangsschema erlaubt, behandelt sie separat über einen float-Zwischenschritt mit Präzisions-Kompromiss.
  • Postgres: numeric(19, 4) ist das portable Pendant, der Postgres-eigene money-Typ hängt an lc_monetary und bleibt für ETL fragil. Ein direktes Try-Pendant fehlt, fn_try_cast_numeric_19_4 schließt die Lücke (set-basiert hilft pg_input_is_valid seit Postgres 16).

Für die Praxis als Entscheidungshilfe:

EingangslageEmpfohlener Weg
Punkt-Notation, reine Zahldirekt TRY_CONVERT(money, …)
Deutsche Notation (Dezimal-Komma)Komma normalisieren, dann konvertieren — das sichere Pattern
Leere Zeichenfolgen möglich (CSV-Import)CASE/TRIM mappt auf NULL, dann TRY_CONVERT
Tausenderpunkte und Dezimal-Komma gemischtvorab vollständig bereinigen oder als Datenqualitätsfehler zurückweisen
E-Notation in Betrags-Spaltenklären, ob sie zum Eingangsschema gehört — sonst als Datenqualitätsfehler behandeln statt via float normalisieren
Mehrstufige Berechnungen (Brutto/Netto, Allokation)decimal(p, s) statt money für die Arithmetik
Cross-Engine-Portabilitätnumeric(19, 4) in Postgres, nicht der Postgres-money-Typ

FAQ

Warum gibt TRY_CONVERT(money, '123,45') 12345.00 zurück und nicht 123.45?

Das Komma in einer Text-Eingabe wird von TRY_CONVERT(money, …) nicht als Dezimaltrennzeichen interpretiert, sondern wie ein Gruppierungszeichen ignoriert. Das Verhalten hängt nicht von der Spracheinstellung der SQL-Server-Session ab, auch ein Server mit deutscher Spracheinstellung ändert nichts daran. Bei deutschsprachigen Eingangsdaten muss das Komma vor der Konvertierung via REPLACE(…, ',', '.') durch einen Punkt ersetzt werden — das sichere Pattern oben übernimmt genau das.

Wie verhindert man, dass ein leeres CSV-Feld zu 0.00 wird?

Vor der Konvertierung explizit auf NULL mappen: CASE WHEN TRIM(@p_input) = '' THEN NULL ELSE @p_input END — genau das übernimmt das sichere Pattern. Ohne diese Vorbehandlung macht TRY_CONVERT(money, N'') aus dem leeren Feld eine 0.00, die sich später nicht mehr von einem echten Null-Betrag unterscheiden lässt. Zu beachten: TRIM erkennt nur normale Leerzeichen (char(32)), Tabs oder anderer Unicode-Leerraum brauchen eine erweiterte Normalisierung.

money oder decimal — wann was?

money ist für reine Speicher-Spalten und einfache Konvertierungen ohne mehrstufige Arithmetik gut geeignet. Sobald Aggregationen, Divisionen oder Multiplikations-Ketten ins Spiel kommen, führt die implizite Zwischen-Rundung auf vier Nachkommastellen zu akkumulierten Fehlern — dann ist decimal(p, s) mit explizit gewählter Skala die bessere Wahl. Faustregel: money an den Systemgrenzen (Import/Export), decimal für die Verarbeitung. Microsoft selbst rät von money für Berechnungen ab und empfiehlt dafür decimal mit mindestens vier Nachkommastellen. Für neue Berechnungslogik ist decimal(p, s) die robustere Wahl.

Warum ist (money) 123.45678 / 100 * 100 nicht 123.45678?

Bei 123.45678 / 100 bleibt der Ergebnistyp money, dem Zwischen-Ergebnis stehen also nur vier Nachkommastellen zur Verfügung. Im konkreten Beispiel wird 123.45678 / 100 zunächst zu 1.2345 gerundet (statt 1.2345678 zu bleiben), die folgende Multiplikation mit 100 ergibt dann 123.4500 — nicht den Ausgangswert. Bei decimal(p, s) wächst die Skala in der Division, der Wert bleibt in diesem Fall vollständig erhalten.

Wann smallmoney statt money?

smallmoney ist auf den Wertebereich ±214 748,3647 begrenzt und belegt nur 4 statt 8 Byte pro Wert. Für Spalten mit garantiert kleinen Werten (Stückpreise, Gebühren, kleinere Beträge) ist das die kompaktere Wahl. Bei jeder Unsicherheit über den maximal möglichen Wert führt der Wechsel auf money zu keinen Nachteilen außer der Speicher-Verdopplung — und vermeidet eine spätere Datentyp-Migration. Für neue Modelle mit Berechnungslogik ist unabhängig davon decimal(p, s) zu erwägen (siehe „money oder decimal“ oben).

Warum liefert TRY_CONVERT(money, …) NULL, obwohl die Zahl gültig aussieht?

Die drei häufigsten Ursachen: mehr als ein Punkt im String (typisch nach einer Komma-Ersetzung, wenn die Quelle Tausenderpunkte enthielt), wissenschaftliche Notation als Text und ein smallmoney-Overflow. Eine Gegenprobe mit TRY_CONVERT(money, …) trennt den Overflow-Fall: Liefert sie einen Wert, war der smallmoney-Wertebereich das Problem. Die gefährlicheren Fälle sind allerdings die ohne NULL — das ignorierte Komma und die leere Zeichenfolge erzeugen stille Falschwerte statt eines sichtbaren Fehlersignals.

Postgres-Pendant für TRY_CONVERT(money, …)?

Für portable Workloads numeric(19, 4) plus der PL/pgSQL-Wrapper fn_try_cast_numeric_19_4 aus der Postgres-Brücke, der die Fehlerklassen invalid_text_representation und numeric_value_out_of_range gezielt zu NULL macht. Der Postgres-eigene money-Typ existiert, hängt aber über lc_monetary am Session-Locale und bleibt für ETL-Workloads fragil.

Verwandte Artikel

ETL-Kontext:

TRY_CONVERT für andere Datentypen:

Grundlagen: