Nullwerte in einer CASE-Anweisung

8

Ich spiele mit ein paar Sachen in SSMS herum, um ein bisschen mehr zu lernen, während ich für meine 70-461-Prüfung lerne, und bin auf ein kleines Auflegen gestoßen. Ich versuche, eine Tabelle zum Herumspielen zu erstellen, damit ich keine der bereits erstellten Tabellen in den AdventureWorks- oder TSQL2012-Datenbanken ändern / löschen muss. Ich habe eine temporäre Tabelle erstellt, um meinen Code zu testen, bevor ich tatsächlich eine Tabelle zum Spielen erstelle. Dies ist der Code, mit dem ich Werte in meine Tabelle einfüge:

DECLARE @i INT = 1
 WHILE @i < 10
    BEGIN
    INSERT INTO #TestEmployeeCountry 
    VALUES ( SUBSTRING('ABCDEFGHIJKLMNOP', @i, 1), 
        CASE (SELECT ABS(CHECKSUM(NEWID()))%10 +1)
            WHEN 1 THEN 'USA'
            WHEN 2 THEN 'CANADA'
            WHEN 3 THEN 'MEXICO'
            WHEN 4 THEN 'UK'
            WHEN 5 THEN 'FRANCE'
            WHEN 6 THEN 'SPAIN'
            WHEN 7 THEN 'RUSSIA'
            WHEN 8 THEN 'CHINA'
            WHEN 9 THEN 'JAPAN'
            WHEN 10 THEN 'INDIA'
        END)
    SET @i = @i + 1
    END;

Das Problem, das ich habe, ist, dass immer wieder die Fehlermeldung "Der Wert NULL kann nicht in die Spalte 'Land', Tabelle 'tempdb.dbo eingefügt werden. # TestEmployeeCountry" angezeigt wird. Dies liegt daran, dass die Spalte "Land" auf NICHT NULL gesetzt ist Mein Code funktioniert für einige der Einfügungen. Das Problem ist, dass ich zufällig NULL-Werte aus meiner case-Anweisung erhalte.

Ich weiß, dass ich zur Behebung dieses Problems leicht eine weitere Zeile mit der Aufschrift "DEFAULT xxxxxx" hinzufügen kann. Ich möchte jedoch verstehen, was vor sich geht, denn basierend auf dem, was ich sehe, sollte ich das nicht tun müssen, oder? Ich dachte, ich hätte meine case-Anweisung richtig geschrieben und nur eine Zahl zwischen 1 und 10 angegeben. Wenn ich nur diese bestimmte select-Anweisung über 1000 Versuche teste, erhalte ich immer eine Zufallszahl zwischen 1 und 10, nichts Größeres oder Kleineres. Kann mir jemand helfen zu verstehen, warum dieser Code versucht, einen NULL-Wert in diese Spalte einzugeben?

user2921015
quelle

Antworten:

8

Warum dies geschieht, wurde bereits von @PaulWhite in der SO-Frage beantwortet: Wie erreicht dieser CASE-Ausdruck die ELSE-Klausel?

Um es zu lösen, sollten Sie das ABS(CHECKSUM(NEWID()))%10 +1Äußere / vor der INSERTAnweisung berechnen, damit es einmal berechnet wird. Etwas wie:

DECLARE @i INT = 1 ;
DECLARE @rand INT ;
 WHILE @i <= 10
   BEGIN
    SET @rand = ABS(CHECKSUM(NEWID()))%10 +1 ;
    INSERT INTO TestEmployeeCountry 
    VALUES ( SUBSTRING('ABCDEFGHIJKLMNOP', @i, 1), 
        CASE @rand
            WHEN 1 THEN 'USA'
            WHEN 2 THEN 'CANADA'
            WHEN 3 THEN 'MEXICO'
            WHEN 4 THEN 'UK'
            WHEN 5 THEN 'FRANCE'
            WHEN 6 THEN 'SPAIN'
            WHEN 7 THEN 'RUSSIA'
            WHEN 8 THEN 'CHINA'
            WHEN 9 THEN 'JAPAN'
            WHEN 10 THEN 'INDIA'
        END) ;
    SET @i = @i + 1 ;
   END ;

Beachten Sie auch, dass mit Ihrem Code die 10 Länder nicht mit gleicher Wahrscheinlichkeit in die Tabelle aufgenommen werden! Das erste Land ( USA) hat eine Chance von 10%, das zweite eine Chance von 9% ( (100%-10%)*10%), das dritte (100%-19%)*10%eine Chance von 8,1% ( ) usw. Damit bleibt eine nicht so geringe Chance (um 1/e), dass keine der 10 ausgewählt wird und der CASEAusdruck geht auf die Standardeinstellung ELSE NULLund Sie erhalten den Fehler. (Sie können die Wahrscheinlichkeiten überprüfen, wenn Sie Nullen in der Spalte zulassen und das SQLfiddle-Skript ausführen .)

Demnach besteht eine andere Möglichkeit zur Lösung darin, die Ausdrücke so zu ändern, dass sie der Ausführung von SQL-Server entsprechen, CASEund alle 10 Fälle haben dieselbe Wahrscheinlichkeit:

    CASE 0
        WHEN ABS(CHECKSUM(NEWID()))%10 THEN 'USA'
        WHEN ABS(CHECKSUM(NEWID()))%9 THEN 'CANADA'
        WHEN ABS(CHECKSUM(NEWID()))%8 THEN 'MEXICO'
        WHEN ABS(CHECKSUM(NEWID()))%7 THEN 'UK'
        WHEN ABS(CHECKSUM(NEWID()))%6 THEN 'FRANCE'
        WHEN ABS(CHECKSUM(NEWID()))%5 THEN 'SPAIN'
        WHEN ABS(CHECKSUM(NEWID()))%4 THEN 'RUSSIA'
        WHEN ABS(CHECKSUM(NEWID()))%3 THEN 'CHINA'
        WHEN ABS(CHECKSUM(NEWID()))%2 THEN 'JAPAN'
        ELSE 'INDIA'
    END
ypercubeᵀᴹ
quelle