Wer einmal eine Ja/Nein-Spalte aus einem Legacy-Export übernommen hat, kennt den Befund: Die Quelle liefert 'J', 'ON' oder ein schlichtes 'x', und TRY_CONVERT(bit, N'J') quittiert die deutsche Notation mit NULL. Eingebaut versteht SQL Server beim bit-Ziel nur Integer-Strings und die Literale 'true'/'false' — jede andere Yes/No-Notation braucht eine eigene Zuordnung.
Auf einen Blick:
- Ein
bitspeichert einen Ja/Nein-Wert:0,1undNULLals dritter Zustand (dreiwertige Logik). SQL Server speichertbit-Spalten platzsparend und packt bis zu 8bit-Spalten einer Zeile in ein Byte. TRY_CONVERT(bit, …)versteht Integer-Strings nach der Regel „alles außer 0 ergibt 1“ und die Literale'true'/'false'— case-insensitiv und Locale-unabhängig. Die stille Falle: Eine leere Zeichenfolge wird zu0konvertiert, nicht zuNULL(gemessen auf SQL Server 2019 und 2022, dokumentiert ist dieser Fall nicht).- Die eigene Funktion
[dbo].[fn_convert_bit]mappt Yes/No-Notationen ('J','JA','ON','x', …) über eine explizite Positivliste (CASE) auf0/1. Unbekannte Werte und die leere Zeichenfolge behandelt sie bewusst alsNULL. - Postgres-Kernbefund:
booleanist dort nativer Typ, und der Casts::booleanakzeptiert von Haus aus mehr Yes/No-Formen als SQL Server. Bei ungültigem Input wirft er allerdings eine Exception — das Try-Verhalten liefert erst der Wrapperfn_try_cast_boolean.
Voraussetzung: TRY_CONVERT existiert seit SQL Server 2012. Die Funktion fn_convert_bit nutzt TRIM und braucht daher SQL Server 2017+ (davor LTRIM(RTRIM(…))-Fallback). Alle Beispiele sind ohne Sample-Datenbank lauffähig. Die Postgres-Beispiele setzen keine bestimmte Version voraus — nur die erwähnte Vorprüfung mit pg_input_is_valid braucht Postgres 16.
Inhalt
- Datentyp
bit— Wertebereich und Speicherbedarf - Text nach
bitkonvertieren - Typisierte Zahlen nach
bitkonvertieren - Sichere Typ-Konvertierung
[dbo].[fn_convert_bit]— eigene Funktion für Nicht-Standard-Notationen- Postgres-Brücke
- Zusammenfassung
- FAQ
- Verwandte Artikel
Datentyp bit — Wertebereich und Speicherbedarf
| Eigenschaft | Wert |
|---|---|
| Wertebereich | 0, 1 und NULL (dreiwertige Logik: 0, 1, „unbekannt“) |
| Speicherbedarf | SQL Server speichert bit-Spalten platzsparend und packt bis zu 8 bit-Spalten einer Zeile in 1 Byte. |
Vergleich mit boolean | SQL Server besitzt keinen nativen BOOLEAN-Datentyp für Spalten oder Variablen. Boolesche Ausdrücke existieren nur intern in Prädikaten und Bedingungen (IS NULL, EXISTS, …). Postgres hat boolean als nativen Datentyp. |
Die NULL-Möglichkeit ist im Import-Kontext relevant: Ein leerer CSV-Wert ist semantisch meist „unbekannt“ und sollte als NULL landen, nicht als 0. Genau das leistet der eingebaute Konverter aber nicht — er macht aus der leeren Zeichenfolge eine 0 (nächste Sektion). Erst die eigene Funktion weiter unten mappt sie konsequent auf NULL.
Text nach bit konvertieren
Text-Eingangswerte kommen typischerweise aus CSV-, JSON- und XML-Importen. Wird ein solcher nvarchar-/varchar-Wert an TRY_CONVERT übergeben, akzeptiert die bit-Konvertierung zwei Eingangs-Kategorien: Integer-Strings, abgebildet nach der Regel „alles außer 0 ergibt 1“, und die Literale 'true'/'false'. Umgebende Leerzeichen sind erlaubt. Jede andere Notation ergibt NULL.
1: SELECT TRY_CONVERT(bit, NULL ) -- NULL
2: SELECT TRY_CONVERT(bit, N'1' ) -- 1
3: SELECT TRY_CONVERT(bit, N'0' ) -- 0
4: SELECT TRY_CONVERT(bit, N'-1' ) -- 1
5: SELECT TRY_CONVERT(bit, N'42' ) -- 1
6: SELECT TRY_CONVERT(bit, N'true' ) -- 1
7: SELECT TRY_CONVERT(bit, N'FALSE' ) -- 0
8: SELECT TRY_CONVERT(bit, N' 1 ' ) -- 1
9: SELECT TRY_CONVERT(bit, N'1.5' ) -- NULL
10: SELECT TRY_CONVERT(bit, N'J' ) -- NULL
11: SELECT TRY_CONVERT(bit, N'YES' ) -- NULL
12: SELECT TRY_CONVERT(bit, N'ON' ) -- NULL
13: SELECT TRY_CONVERT(bit, N'x' ) -- NULL
14: SELECT TRY_CONVERT(bit, N'' ) -- 0
15: SELECT TRY_CONVERT(bit, N' ' ) -- 0
16: SELECT TRY_CONVERT(bit, N'-' ) -- 0
Die Zeilen zeigen im Einzelnen:
- Zeilen 2–5: Integer-Strings folgen der Regel „alles außer 0 ergibt 1“. Auch
'-1'und'42'werden zu1. Das ist dokumentierte Semantik: Jeder Nicht-Null-Wert wird beimbit-Ziel zu1, eine Wertebereichs-Prüfung findet nicht statt. - Zeilen 6–7: Die Literale
'true'/'false'sind case-insensitiv — das gilt auch unter einer case-sensitiven oder binären Kollation (gemessen mitCOLLATE Latin1_General_CS_ASundLatin1_General_BIN2). Die Konvertierung ist außerdem Locale-unabhängig:SET LANGUAGEändert an keinem Ergebnis dieses Blocks etwas. - Zeile 8: Umgebende Leerzeichen sind erlaubt. Das gilt nur für das normale Leerzeichen — mit einem Tab an derselben Stelle lieferte die Messung
NULL. - Zeile 9: Dezimal-Darstellungen als Text scheitern, auch ein harmlos wirkendes
'1.0'. Der Parser akzeptiert nur ganzzahlige Darstellungen. - Zeilen 10–13: Yes/No-Notationen kennt der Parser nicht. Deutsche
'J', englische'YES', die Switch-Notation'ON'und der historische Marker'x'fallen alle aufNULL. - Zeilen 14–16: Die leere Zeichenfolge, ein String nur aus Leerzeichen und ein einzelnes Vorzeichen (
'-','+') werden zu0konvertiert. Das ist gemessenes Verhalten (SQL Server 2019 und 2022, identisch fürCAST,TRY_CASTundTRY_CONVERT) — die Microsoft-Dokumentation legt diesen Fall nicht fest. Die Integer-Ziele zeigen dasselbe Ergebnis:TRY_CONVERT(int, N'')liefert ebenfalls0, siehe Datenqualität in SQL Server // TRY_CONVERT für bigint, int, smallint und tinyint sicher anwenden.
Kernaussage: Ein leeres Feld ist im Import semantisch ein „unbekannt“, TRY_CONVERT(bit, …) macht daraus aber den fachlichen Wert 0 — still, ohne Fehler, ohne NULL. Ein '0' aus der Quelle und ein leeres Feld sind im Ziel danach nicht mehr unterscheidbar. Wo das falsch ist (der Regelfall bei CSV-Importen), mappt das Pattern aus Sichere Typ-Konvertierung die leere Zeichenfolge vorab auf NULL.
Typisierte Zahlen nach bit konvertieren
Kommt der Eingangswert bereits typisiert an, etwa als Integer, decimal, float oder money, reduziert sich das Verhalten auf eine einzige Regel: 0 wird zu 0, jeder andere Wert wird zu 1.
1: SELECT TRY_CONVERT(bit, 1) -- 1
2: SELECT TRY_CONVERT(bit, 0) -- 0
3: SELECT TRY_CONVERT(bit, -1) -- 1
4: SELECT TRY_CONVERT(bit, 42) -- 1
5: SELECT TRY_CONVERT(bit, 0.5) -- 1
6: SELECT TRY_CONVERT(bit, 123456E-3) -- 1
7: SELECT TRY_CONVERT(bit, CAST(0.50 AS money)) -- 1
8: SELECT TRY_CONVERT(bit, CAST(0.00 AS money)) -- 0
Die Zeilen zeigen im Einzelnen:
- Zeilen 3–4: Vorzeichen und Größe spielen keine Rolle —
-1und42werden gleichermaßen zu1. Eine Wertebereichs-Prüfung findet nicht statt, auch derbigint-Maximalwert wird zu1. - Zeilen 5–6: Dezimalzahlen und
float-Literale in wissenschaftlicher Notation werden weder gerundet noch trunkiert. Die „alles außer 0“-Regel greift vor jeder Stellen-Betrachtung:0.5wird zu1. - Zeilen 7–8: Auch
moneyfolgt der Regel — nur die exakte0ergibt0.
Kernaussage: Die Konvertierung typisierter Zahlen nach bit kennt weder Rundung noch Trunkierung noch eine Wertebereichs-Grenze, nur die dokumentierte Abbildung „0 bleibt 0, alles andere wird 1“. Das Ergebnis kann von der Integer-Intuition abweichen: TRY_CONVERT(int, 0.5) trunkiert zu 0, TRY_CONVERT(bit, 0.5) liefert 1. Auch eine strenge 0/1-Validierung leistet die Konvertierung nicht — 42 wird still zu 1, ohne Hinweis auf den unerwarteten Eingangswert. Wenn fachlich nur exakt 0 und 1 gültig sind oder eine Schwelle gemeint ist („ab x gilt Ja“), gehört diese Prüfung als explizite Vergleichs-Logik in die Abfrage, nicht in die Typ-Konvertierung.
Sichere Typ-Konvertierung
„Sicher“ meint in dieser Serie fehlertolerant: kein Abbruch, NULL statt Laufzeitfehler. Diese Eigenschaft bringt TRY_CONVERT(bit, …) von Haus aus mit. Semantisch korrekt ist das Ergebnis damit noch nicht: TRY_CONVERT beantwortet die Frage, ob SQL Server einen Wert konvertieren kann — nicht die Frage, ob der Wert fachlich gültig ist. Zwei Sonderfälle aus den Sektionen oben brauchen im Import-Pfad deshalb eine explizite Behandlung:
- Leere Zeichenfolge →
0: Ein leeres CSV-Feld steht meist für „unbekannt“ und gehört alsNULLins Ziel, nicht als fachliches „Nein“. Die leere Zeichenfolge muss deshalb vor demTRY_CONVERTaufNULLgemappt werden — dasselbe Pattern wie bei den Integer-Typen. - Unbekannte Notation →
NULL:'J','YES'oder'x'fallen still aufNULL. Damit verschmelzen drei verschiedene Sachverhalte im selben Ziel-NULL: Die Quelle hatNULLgeliefert, die Quelle hat ein leeres Feld geliefert (nach dem Vorab-Mapping), oder die Notation ist unbekannt. EinNULLim Ziel ist deshalb keine ausreichende Fehlerdiagnose. Wer die Fälle unterscheiden muss, speichert Rohwert und konvertierten Wert getrennt oder führt eine eigene Konvertierungs-Status-Spalte mit (Gegenprobe: siehe FAQ).
Das Anwendungs-Beispiel löst den ersten Sonderfall:
1: DECLARE @p_input AS nvarchar(30);
2: SET @p_input = N'';
3:
4: SELECT TRY_CONVERT( bit
5: , CASE WHEN TRIM(@p_input) = '' THEN NULL ELSE @p_input END
6: ) AS [Output]; -- NULL statt 0
Zwei Einschränkungen gehören zu dem Pattern dazu:
- Eingabegrammatik:
TRIMentfernt ohne weitere Angabe nur das normale Leerzeichen (char(32)). Tabs oder anderen Unicode-Leerraum erkennt das Pattern nicht als „leer“, und derbit-Parser hat sie in der Messung ebenfalls nicht akzeptiert — solche Werte enden alsNULL. Können sie in den Quelldaten vorkommen, muss die Normalisierung sie explizit behandeln. - Die Notations-Lücke bleibt: Das Pattern behebt nur den Leere-Zeichenfolge-Fall. Yes/No-Notationen jenseits von Integer-Strings und
'true'/'false'brauchen eine eigene Zuordnung — die nächste Sektion.
Genau diese Zuordnung übernimmt [dbo].[fn_convert_bit], und sie behandelt die leere Zeichenfolge bewusst als NULL-Fall: Nach dem TRIM fällt sie durch die CASE-Liste auf ELSE NULL — das ist Vertragslogik der Funktion, nicht Verhalten des SQL-Server-Parsers. Wie sich das Pattern in einen ETL-Prozess mit Materialisierung und Fehler-Identifikation einbettet, zeigt Design Pattern // Sichere Typ-Konvertierung mit T-SQL.
[dbo].[fn_convert_bit] — eigene Funktion für Nicht-Standard-Notationen
In ETL-Pipelines tauchen aus Legacy-Quellen Yes/No-Notationen auf, die TRY_CONVERT(bit, …) nicht abbildet: deutsche 'J'/'JA'/'N'/'NEIN', englische 'Y'/'YES'/'NO', Switch-Notationen 'ON'/'OFF', dazu Markierungen aus manchen Legacy-Beständen, in denen 'x' für „gesetzt“ und '-' für „nicht gesetzt“ steht. Gerade der Bindestrich ist quellspezifisch: In anderen Beständen bedeutet '-' „fehlend“ oder „nicht anwendbar“ — dann gehört er nicht auf 0, sondern auf NULL. Die folgende Funktion mappt die Notationen ihrer Quelle über eine explizite Positivliste deterministisch auf 0/1 und liefert NULL für unbekannte Werte.
Beschreibung
Konvertiert einen übergebenen Eingangswert in den Zieldatentyp bit. Kann der Eingangswert nicht zugeordnet werden, wird NULL zurückgegeben. Der übergebene Wert wird vor dem Vergleich mit UPPER normalisiert. Die vorgesehenen ASCII-Notationen sind damit case-insensitiv, bei Nicht-ASCII-Zeichen ist UPPER kollationsabhängig. Leerzeichen am Anfang und Ende werden ignoriert (TRIM). Eine leere Zeichenfolge fällt nach dem TRIM durch die CASE-Liste und wird zu NULL — anders als beim direkten TRY_CONVERT, das 0 liefert.
Syntax
1: [dbo].[fn_convert_bit](@p_value AS nvarchar(50))
Argumente
p_value— der umzuwandelnde Eingangswert. Parameter-Typ istnvarchar(50)statt der knapperennvarchar(5)aus der Erstfassung. Längere Eingaben würden am Parameter sonst still abgeschnitten, bevorTRIMgreift: Aus' FALSE'(6 Zeichen) macht einnvarchar(5)-Parameter ein' FALS', das dieCASE-Liste nicht mehr erkennt. Für eine konkrete Quelle richtet sich die Länge nach dem Quellschema.
Rückgabe
Gibt den umgewandelten Wert als bit zurück, wenn die Umwandlung erfolgreich ist. Kann der Eingangswert nicht zugeordnet werden, wird NULL zurückgegeben.
Unterstützte Eingangswerte
Eingangswert → 1 | Eingangswert → 0 |
|---|---|
J | N |
JA | NEIN |
Y | NO |
YES | — |
TRUE | FALSE |
ON | OFF |
1, -1 | 0 |
x | - |
Für die hier verwendeten ASCII-Notationen arbeitet die Funktion case-insensitiv: UPPER normalisiert den Eingangswert vor dem CASE-Vergleich, ja, Ja und JA landen also auf demselben Mapping. Bei Notationen außerhalb des ASCII-Bereichs hängt UPPER von der Kollation ab: Unter türkischer Kollation wird aus 'nein' etwa 'NEİN' mit İ-Punkt, das die Liste nicht mehr trifft. Die Tabelle ist die Positivliste der Funktion — vollständig ist sie immer nur gegenüber einer konkreten Quelle, eine allgemeingültige Liste aller Ja/Nein-Notationen gibt es nicht. Die Funktion ist deshalb als Ausgangs-Skelett zu verstehen. Pro Datenquelle wird sie an die tatsächlich gelieferten Notationen angepasst (z. B. 'wahr'/'falsch', 'sí'/'no').
Code
Vollständige Funktions-Definition:
1: CREATE FUNCTION [dbo].[fn_convert_bit] (@p_value AS nvarchar(50))
2: RETURNS bit
3: AS
4: BEGIN
5: DECLARE @return_value AS bit;
6:
7: SET @p_value = UPPER(TRIM(@p_value));
8: SET @return_value = CASE @p_value
9: WHEN N'J' THEN 1
10: WHEN N'JA' THEN 1
11: WHEN N'Y' THEN 1
12: WHEN N'YES' THEN 1
13: WHEN N'N' THEN 0
14: WHEN N'NEIN' THEN 0
15: WHEN N'NO' THEN 0
16: WHEN N'TRUE' THEN 1
17: WHEN N'FALSE' THEN 0
18: WHEN N'ON' THEN 1
19: WHEN N'OFF' THEN 0
20: WHEN N'X' THEN 1 -- quellspezifisch
21: WHEN N'-1' THEN 1
22: WHEN N'1' THEN 1
23: WHEN N'0' THEN 0
24: WHEN N'-' THEN 0 -- quellspezifisch
25: ELSE NULL
26: END;
27:
28: RETURN @return_value;
29: END;
Demo-Aufrufe
16 Aufrufe, mit dem jeweils erwarteten Ergebnis als Kommentar:
1: SELECT [dbo].[fn_convert_bit](N'1'); -- 1
2: SELECT [dbo].[fn_convert_bit](N'0'); -- 0
3: SELECT [dbo].[fn_convert_bit](N'-1'); -- 1
4: SELECT [dbo].[fn_convert_bit](N'J'); -- 1
5: SELECT [dbo].[fn_convert_bit](N'ja'); -- 1 (case-insensitiv über UPPER im Funktions-Body)
6: SELECT [dbo].[fn_convert_bit](N'nein'); -- 0
7: SELECT [dbo].[fn_convert_bit](N'x'); -- 1 (Legacy-Marker: gesetzt)
8: SELECT [dbo].[fn_convert_bit](N'-'); -- 0 (Legacy-Marker: nicht gesetzt)
9: SELECT [dbo].[fn_convert_bit](N'true'); -- 1
10: SELECT [dbo].[fn_convert_bit](N'false'); -- 0
11: SELECT [dbo].[fn_convert_bit](N'ON'); -- 1
12: SELECT [dbo].[fn_convert_bit](N'OFF'); -- 0
13: SELECT [dbo].[fn_convert_bit](N' ja '); -- 1 (Leerzeichen-Padding, TRIM greift)
14: SELECT [dbo].[fn_convert_bit](N''); -- NULL (leere Zeichenfolge; direktes TRY_CONVERT ergäbe 0)
15: SELECT [dbo].[fn_convert_bit](N'?'); -- NULL (unbekannter Eingangswert)
16: SELECT [dbo].[fn_convert_bit](NULL); -- NULL (NULL-Input bleibt NULL)
Postgres-Brücke
In Postgres ist die Lage komfortabler: boolean ist ein nativer Datentyp, ein bit-Ersatz ist nicht nötig. Der Direkt-Cast s::boolean versteht ohne Zusatz-Aufwand eine deutlich umfangreichere Yes/No-Liste als SQL Servers bit-Parser:
1: SELECT 't'::boolean; -- true
2: SELECT 'true'::boolean; -- true
3: SELECT 'TRUE'::boolean; -- true (case-insensitiv)
4: SELECT ' true '::boolean; -- true (umgebender Leerraum wird entfernt)
5: SELECT 'tr'::boolean; -- true (eindeutiges Präfix von true)
6: SELECT 'y'::boolean; -- true
7: SELECT 'yes'::boolean; -- true
8: SELECT 'on'::boolean; -- true
9: SELECT '1'::boolean; -- true
10:
11: SELECT 'f'::boolean; -- false
12: SELECT 'n'::boolean; -- false
13: SELECT 'no'::boolean; -- false
14: SELECT 'off'::boolean; -- false
15: SELECT '0'::boolean; -- false
Drei Unterschiede gegenüber SQL Server:
- Breitere Eingabeliste:
't'/'y'/'yes'/'on'/'1'und ihrefalse-Pendants, case-insensitiv und mit Leerraum-Toleranz. Sogar eindeutige Präfixe akzeptiert der Parser ('tr','ye'). Nur das mehrdeutige'o'lehnt er ab, weil es'on'wie'off'sein könnte. - Nur
'1'und'0'als Ziffern: Die T-SQL-Regel „alles außer 0 ergibt 1“ gibt es nicht —'-1'::booleanund'42'::booleanwerfen eine Exception. Numerische Wahrheitswerte aus einer SQL-Server-Quelle müssen in Postgres vorab auf'0'/'1'normalisiert werden. - Exception statt stiller Werte: Ungültige Eingaben wie
'J'und auch die leere Zeichenfolge brechen mitinvalid input syntax for type booleanab (SQLSTATE22P02, Fehlerklasseinvalid_text_representation). Ein eingebautes Try-Pendant existiert nicht, auch in Postgres 18 nicht.
Das NULL-statt-Exception-Verhalten plus die deutschen Notationen liefert ein PL/pgSQL-Wrapper mit derselben CASE-Zuordnung wie die T-SQL-Funktion:
1: CREATE OR REPLACE FUNCTION fn_try_cast_boolean
2: (
3: IN p_input text
4: )
5: RETURNS boolean
6: LANGUAGE plpgsql
7: IMMUTABLE
8: AS $function$
9: DECLARE
10: l_normalized text;
11: BEGIN
12:
13: IF p_input IS NULL OR TRIM(p_input) = '' THEN
14: RETURN NULL;
15: END IF;
16:
17: l_normalized := UPPER(TRIM(p_input));
18:
19: RETURN CASE l_normalized
20: WHEN 'J' THEN true
21: WHEN 'JA' THEN true
22: WHEN 'Y' THEN true
23: WHEN 'YES' THEN true
24: WHEN 'TRUE' THEN true
25: WHEN 'T' THEN true
26: WHEN 'ON' THEN true
27: WHEN '1' THEN true
28: WHEN '-1' THEN true
29: WHEN 'X' THEN true -- quellspezifisch
30: WHEN 'N' THEN false
31: WHEN 'NEIN' THEN false
32: WHEN 'NO' THEN false
33: WHEN 'FALSE' THEN false
34: WHEN 'F' THEN false
35: WHEN 'OFF' THEN false
36: WHEN '0' THEN false
37: WHEN '-' THEN false -- quellspezifisch
38: ELSE NULL
39: END;
40:
41: END;
42: $function$;
43:
44: SELECT fn_try_cast_boolean('J'); -- true
45: SELECT fn_try_cast_boolean(' ja '); -- true
46: SELECT fn_try_cast_boolean('x'); -- true
47: SELECT fn_try_cast_boolean('foo'); -- NULL
48: SELECT fn_try_cast_boolean(''); -- NULL
Zwei Eigenheiten unterscheiden diesen Wrapper von seinen Geschwistern in den anderen Artikeln der Serie. Erstens braucht er keinen EXCEPTION-Block: Die CASE-Zuordnung wirft nie, unbekannte Werte laufen in ELSE NULL. Damit entfällt der Kosten-Aufschlag, den die Postgres-Doku für Blöcke mit Exception-Handler nennt. Zweitens erbt er nichts vom nativen Parser: Präfix-Formen wie 'tr' stehen nicht in der Liste und ergeben NULL — die CASE-Liste ist der Vertrag. Wer stattdessen beim nativen Cast bleiben will, prüft seit Postgres 16 mit pg_input_is_valid('J', 'boolean') set-basiert vor, ob ein Wert konvertierbar ist, ohne einen fehlschlagenden Cast auszulösen. Das ist ein Vorprüf-Pattern, kein Try-Cast: Geprüft und konvertiert wird in zwei getrennten Schritten gegen dieselbe Eingabe.
| SQL Server | Postgres-Pendant | Bemerkung |
|---|---|---|
TRY_CONVERT(bit, '1') | '1'::boolean oder fn_try_cast_boolean('1') | Built-in identisch |
TRY_CONVERT(bit, 'true') | 'true'::boolean oder fn_try_cast_boolean('true') | Built-in identisch |
TRY_CONVERT(bit, 'J') → NULL | 'J'::boolean → Exception, fn_try_cast_boolean('J') → true | Wrapper deckt deutsche Notation |
TRY_CONVERT(bit, '') → 0 | ''::boolean → Exception, fn_try_cast_boolean('') → NULL | dasselbe leere Feld, drei Ergebnisse |
[dbo].[fn_convert_bit](N'YES') | fn_try_cast_boolean('YES') | funktionale Entsprechung |
Zusammenfassung
- Konvertierung nach
bitist zweistufig zu denken: erst prüfen, ob der eingebaute Konverter die Quelle abdeckt (Integer-Strings nach der „alles außer 0“-Regel plus'true'/'false'), erst dann eine eigene Funktion einsetzen. - Der wichtigste Sonderfall des Built-ins: Leere Zeichenfolgen, Leerzeichen-Strings und einzelne Vorzeichen werden zu
0konvertiert (gemessen, nicht dokumentiert) — ein leeres CSV-Feld wird so zum fachlichen „Nein“. Das sichere Pattern mappt die leere Zeichenfolge perCASE/TRIMvorab aufNULL. [dbo].[fn_convert_bit]übernimmt Yes/No-Notationen ('J','JA','ON','x', …) über eine explizite Positivliste. Unbekannte Werte und die leere Zeichenfolge behandelt sie bewusst alsNULL— das passt zur dreiwertigen Logik (0/1/NULL) desbit-Typs.- Postgres-Pendant:
booleannativ mit breiterer Eingabeliste ('t','yes','on', eindeutige Präfixe), aber Exception stattNULLbei ungültigem Input.fn_try_cast_booleanliefert das Try-Verhalten und die deutschen Notationen.
Für die Praxis als Entscheidungshilfe:
| Eingangslage | Empfohlener Weg |
|---|---|
Quelle liefert nur '0'/'1'/'true'/'false' | direkt TRY_CONVERT(bit, …) |
| Leere Zeichenfolgen möglich (CSV-Import) | sicheres Pattern: CASE/TRIM mappt auf NULL, dann TRY_CONVERT |
Typisierte Zahlen (0/1/-1, Berechnungs-Ergebnisse) | direkt TRY_CONVERT(bit, …) — „alles außer 0 ergibt 1“ |
Yes/No-Notationen ('J', 'YES', 'ON', 'x') | fn_convert_bit mit expliziter Positivliste |
| Gemischte oder unbekannte Notationen | DISTINCT-Inventur der Quelle, Positivliste verbindlich festhalten |
NULL unklarer Herkunft im Ziel-Feld | set-basierte Gegenprobe (siehe FAQ) |
FAQ
TRY_CONVERT(bit, 'J') NULL zurück? Die bit-Konvertierung akzeptiert aus Text nur Integer-Strings ('0', '1', '-1', jede Zahl außer 0 ergibt 1) und die Literale 'true'/'false' (case-insensitiv). 'J' ist keines davon, also fällt der Aufruf auf NULL zurück. Im ETL-Pfad ist das gewollt — TRY_CONVERT löst keine Exception aus, sondern signalisiert „passt nicht“ über NULL. Für Yes/No-Notationen wie 'J' braucht es eine eigene Funktion mit CASE-Zuordnung (siehe [dbo].[fn_convert_bit]).
TRY_CONVERT(bit, N'') zu 0 statt NULL? SQL Server konvertiert die leere Zeichenfolge beim bit-Ziel zu 0 — die Konvertierung gilt als erfolgreich, es gibt weder Fehler noch NULL (gemessenes Verhalten auf SQL Server 2019 und 2022, von der Microsoft-Doku nicht festgelegt). Dasselbe gilt für Strings nur aus Leerzeichen und für ein einzelnes Vorzeichen ('-', '+'), und dieselbe 0 liefert auch die Integer-Konvertierung TRY_CONVERT(int, N''). Im Import ist das selten gemeint, denn ein leeres Feld steht für „unbekannt“, nicht für „Nein“. Das sichere Pattern mappt die leere Zeichenfolge deshalb per CASE/TRIM vorab auf NULL, und fn_convert_bit hat genau dieses Verhalten eingebaut.
bit und boolean? SQL Server besitzt keinen nativen BOOLEAN-Datentyp für Spalten oder Variablen. Boolesche Ausdrücke existieren nur intern in Prädikaten und Bedingungen (IS NULL, EXISTS, WHERE-Klauseln). Wer Wahrheitswerte in einer Tabelle ablegen will, nutzt bit als Ersatz. Postgres dagegen hat boolean als nativen Datentyp und akzeptiert beim Cast eine breitere Yes/No-Liste ('t'/'true'/'y'/'yes'/'on'/'1' und Pendants). Praktisch: In einer Cross-Engine-ETL-Pipeline ist bit (SQL Server) ↔ boolean (Postgres) das semantische Pendant — beide bilden zwei Wahrheitszustände plus NULL ab. Identisch sind die Typen damit nicht: Eingabegrammatik und Fehlerverhalten unterscheiden sich (siehe Postgres-Brücke).
bit performant in einer breiten Tabelle? SQL Server speichert mehrere bit-Spalten einer Zeile gemeinsam in einem Byte (bis zu 8 Spalten in 1 Byte). Die Gruppierung übernimmt die Storage-Engine intern — die Deklarationsreihenfolge im CREATE TABLE muss dafür nicht künstlich umgestellt werden. Bei einzelnen bit-Spalten ist der Speicher-Vorteil gegenüber tinyint in der Praxis meist gering. Der Unterschied ist primär semantisch: bit signalisiert „dreiwertige Logik mit 0/1/NULL“, tinyint signalisiert „kleine ganze Zahl 0–255“.
'YES', 'Y', '1' und 'true' liefert? Die fn_convert_bit-Funktion erweitern (alle vier Werte sind dort schon abgedeckt) — oder im SSIS-Derived-Column-Task vorverarbeiten, falls die Konvertierung in der Pipeline statt im T-SQL stattfindet. Wichtig ist die Vollständigkeit der Positivliste gegenüber der Quelle: Jede tatsächlich vorkommende Notation muss in der CASE-Liste stehen, sonst landen Datensätze auf NULL und der Import wirkt unvollständig. Im Zweifel pro Datenquelle eine Inventur der Distinct-Werte ziehen (SELECT DISTINCT col FROM stage o. ä.) und die Liste verbindlich festhalten.
TRY_CONVERT(bit, …) NULL, obwohl der Wert gültig aussieht? Beim bit-Ziel gibt es drei NULL-Ursachen: Die Quelle hat NULL geliefert, die Notation ist dem Parser unbekannt ('J', 'YES', 'x'), oder unsichtbare Zeichen stören — schon ein Tab statt eines Leerzeichens reicht, denn der Parser toleriert nur das normale Leerzeichen. Die set-basierte Gegenprobe SELECT DISTINCT spalte FROM quelle WHERE spalte IS NOT NULL AND TRY_CONVERT(bit, spalte) IS NULL listet genau die Werte auf, die der Parser nicht kennt. Das ist zugleich die Basis für die nächste Erweiterung der CASE-Liste von fn_convert_bit.
TRY_CONVERT(bit, …)? Direkt: s::boolean (siehe Postgres-Brücke). Der Built-in deckt 't'/'true'/'y'/'yes'/'on'/'1' samt Pendants und eindeutigen Präfixen ab — mehr als SQL Servers bit-Parser. Bei ungültigem Input wirft er allerdings eine Exception, und ein eingebautes try_cast hat auch Postgres 18 nicht nachgeliefert. Das Try-Verhalten liefert der Wrapper fn_try_cast_boolean aus der Postgres-Brücke. Die Konvertierbarkeit lässt sich seit Postgres 16 zusätzlich mit pg_input_is_valid set-basiert vorprüfen.
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.
- Design Pattern // Sichere Typ-Konvertierung mit T-SQL — das übergeordnete Pattern (Materialisierung + Fehler-Identifikation), das diese
TRY_CONVERT-Bausteine einbettet.
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 decimal und numeric 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
Grundlagen:
- Datenqualität // Grundlagen der Typ-Konvertierung mit T-SQL — CAST, CONVERT, TRY_CAST und TRY_CONVERT im Vergleich.