T-SQL CASE und die implizite Datentypkonvertierung
Wenn man in einem Ausdruck einen CASE-Block verwendet, so ist dies auf den ersten Blick noch keine Besonderheit. Vergisst man jedoch dabei, dass SQL Server eine implizite Datentypkonvertierung vornimmt, so kann dies zu fehlerhaften Ergebnissen führen die noch dazu sehr schwer zu finden sind.
Betrachten wir hierfür einmal folgendes Beispiel:
| T-SQL | | copy code | | ? |
| 01 | DECLARE @AlteKndNr VARCHAR(15) |
| 02 | DECLARE @Von VARCHAR(15) |
| 03 | DECLARE @Auf VARCHAR(15) |
| 04 | DECLARE @Regel INT |
| 05 | |
| 06 | SET @AlteKndNr = 'K011110999-VIP' |
| 07 | |
| 08 | SET @Regel = 1 |
| 09 | SET @Von = CASE @Regel WHEN 1 THEN '099' WHEN 2 THEN '0111' ELSE 0 END |
| 10 | SET @Auf = CASE @Regel WHEN 1 THEN '033' WHEN 2 THEN '0000' ELSE 0 END |
| 11 | |
| 12 | SELECT NeueKndNr = REPLACE(@AlteKndNr, @Von, @Auf), @Von, @Auf |
| 13 | |
| 14 | SET @Regel = 2 |
| 15 | SET @Von = CASE @Regel WHEN 1 THEN '099' WHEN 2 THEN '0111' ELSE 0 END |
| 16 | SET @Auf = CASE @Regel WHEN 1 THEN '033' WHEN 2 THEN '0000' ELSE 0 END |
| 17 | |
| 18 | SELECT NeueKndNr = REPLACE(@AlteKndNr, @Von, @Auf), @Von, @Auf |
| 19 | |
| 20 | -- ------------------------------------------------------------------------- |
| 21 | -- Ergebnisse: |
| 22 | -- |
| 23 | -- NeueKdNr bei @Regel = 1: K011110339-VIP = OK |
| 24 | -- NeueKdNr bei @Regel = 2: K0010999-VIP = FALSCH |
| 25 | -- K000010999-VIP = Das währe richtig! |
| 26 | -- ------------------------------------------------------------------------- |
| 27 |
Wie man sehen kann wird bei @Regel=2 eine falsche Konvertierung durchgeführt. Dies liegt an der oben besprochenen impliziten Konvertierungsregel von SQL Server. Wenn mehrere Datentypen in einem Ausdruck vorkommen so werden diese in einen Zieldatentyp konvertiert.
Der Typ des Zieldatentyps ist der Typ des Wertes der in folgender Tabelle den höchsten Prioritätswert (1) aufweist.
In unserem Fall wird im CASE-Block in den When-Zweigen ein String zurückgegeben, im Else-Zweig hingegen ein Integerwert! Obwohl der Else-Zweig nicht angesprochen wird, ist der Gesamtdatentyp des CASE-Blocks gem. Konvertierungstabelle ein Integerwert, da dieser die höhere Priorität gegenüber den varchar-Werten der When-Zweige aufweist.
Wenn man also den Else-Zweig des Case-Blocks mit Else ‘0′ definiert (man beachte die Hochkommas), dann wird auch das richtige Ergebnis ausgegeben.
Hier die Tabelle die die Prioritäten bei der impliziten Typkonvertierung aufzeigt:
| Priorität | Datentyp |
| 1 | Benuter-Definierter Typ |
| 2 | sql_variant |
| 3 | xml |
| 4 | datetime |
| 5 | smalldatetime |
| 6 | float |
| 7 | real |
| 8 | decimal |
| 9 | money |
| 10 | smallmoney |
| 11 | bigint |
| 12 | int |
| 13 | smallint |
| 14 | tinyint |
| 15 | bit |
| 16 | ntext |
| 17 | text |
| 18 | image |
| 19 | timestamp |
| 20 | uniqueidentifier |
| 21 | nvarchar |
| 22 | nchar |
| 23 | varchar |
| 24 | char |
| 25 | varbinary |
| 26 | binary |
have fun
Facebook
XING
META-SQL