Home > SQL-Server 2005 > TSQL Fehler bei Case (simple Version)

TSQL Fehler bei Case (simple Version)

Die Case-Anweisung von T-SQL verhält sich sehr interessant (fehlerhaft?) bei Ausdrücken die in der einfachen Version des Statements in der Case-Expression angegeben werden.

Die einfache Syntax siehe wie folgt aus:

 T-SQL |  copy code |? 
1
CASE input_expression
2
     WHEN when_expression THEN result_expression
3
    [ ...n ]
4
     [
5
    ELSE else_result_expression
6
     ]
7
END

Um das Problem zu demonstrieren, möchte ich einmal das folgende Statement zur Diskussion stellen:

 T-SQL |  copy code |? 
01
DECLARE @i INT
02
 
03
SET @i = 0
04
 
05
WHILE @i<10
06
BEGIN
07
	PRINT
08
	CASE CONVERT(INT,RAND()*5+1)
09
		WHEN 1 THEN 10
10
		WHEN 2 THEN 20
11
		WHEN 3 THEN 30
12
		WHEN 4 THEN 40
13
		WHEN 5 THEN 50
14
		WHEN 6 THEN 60
15
		ELSE 0
16
	END
17
	SET @i = @i + 1
18
END

Das CASE-Statement verwendet die Random-Funktion RAND().

Diese Funktion liefert Werte zwischen 0 und 1 zurück. Multipliziert man nun den Rückgabewert mit 5 sollten also bis dahin Zahlen zwischen 0 und 5 zurückgeliefert werden. Um 0-Werte auszuschließen wird abschließend noch 1 dazu addiert und der endgültige Wertebereich liegt zwischen 1 und 6.

Soweit so gut.

Lässt man jedoch die oben beschriebene Schleife laufen, erhält man als Ergebnis aus dem CASE-Austruck auch den ELSE-Wert 0 zurückgeliefert. Dies darf jedoch aufgrund der Berechnung eigentlich gar nicht geschehen!

Das Problem liegt hier in der Art wie die CASE-Funktion die input_expression behandelt. Anscheinend wird der Ausdruck trotz CAST/CONVERT nicht korrekt in seinem Datentyp interpretiert und liefert als Ergebnis wahrscheinlich einen FLOAT-Wert zurück.

(Zur Behandlung von Typkonvertierungen siehe “T-SQL CASE und die implizite Datentypkonvertierung”)

Dieser Wert ist durch die Random-Funktion allerdings nicht im Einzelfall zu bestimmen und kann, wenn überhaupt, nur durch aufwändige Tests ermittelt werden.

Als Regel können wir hier also festhalten:

Wenn eine CASE-Inputexpression ein nicht deterministisches Ergebnis liefert, ist das Verhalten der Funktion auf das genaueste zu testen.

Als Workaround muss man dafür sorgen, dass der Wert für die Inputexpression nicht im CASE berechnet wird, sondern ggf. vorher. Sei es in einer CTE, wenn man den Wert innerhalb einer Abfrage benötigt, oder vorher in einer Variablen.

Ein Beispiel für die Version mit der Variablen findet man nachfolgend:

 T-SQL |  copy code |? 
01
DECLARE @i INT
02
DECLARE @w INT
03
 
04
SET @i = 0
05
 
06
WHILE @i<10
07
BEGIN
08
            SET @w = CONVERT(INT,RAND()*5+1)
09
            PRINT
10
            CASE @w
11
                 WHEN 1 THEN 10
12
                 WHEN 2 THEN 20
13
                 WHEN 3 THEN 30
14
                 WHEN 4 THEN 40
15
                 WHEN 5 THEN 50
16
                 WHEN 6 THEN 60
17
                 ELSE 0
18
            END
19
            SET @i = @i + 1
20
END

Wenn jemand einen anderen Weg, oder eine Erklärung für dieses absonderliche Verhalten hat, ist er/sie aufgefordert dies in den Kommentaren der interessierten Öffentlichkeit mitzuteilen.

;)

 

KategorienSQL-Server 2005
  1. Bisher keine Kommentare
  1. Bisher keine Trackbacks