CASEステートメントのnull値


8

私は70-461試験に向けて勉強しているときにSSMSでいくつかのことをさらに学習するために遊んでいて、少しハングアップに遭遇しました。私は、いじくり回すためのテーブルを作成しようとしているので、AdventureWorksまたはTSQL2012データベースで既に作成されているテーブルを変更/削除する必要はありません。実際に使用するテーブルを作成する前に、コードをテストするための一時テーブルを作成しました。これは、テーブルに値を挿入するために使用するコードです。

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;

私が抱えている問題は、「値NULLを列 'Country'、テーブル 'tempdb.dbo。#TestEmployeeCountryに挿入できません」というエラーが発生し続けることですこれは、Country列をNOT NULLに設定しているためです。私のコードは一部の挿入で機能しますが、問題は、case文からNULL値をランダムに取得することです。

これを修正するには、「DEFAULT xxxxxx」という別の行を簡単に追加できることを知っていますが、何が起こっているのかを理解したいのです。私はケースステートメントを正しく記述し、1〜10の数字のみを与え、1000回を超える特定の選択ステートメントのみをテストすると、常に1〜10の乱数を取得しました。このコードがその列にNULL値を入力しようとする理由を理解するのを手伝ってくれる人はいますか?

回答:


8

なぜこれが起こるのかは、SOの質問で@PaulWhiteによって既に回答されています:このCASE式はどのようにELSE句に到達しますか?

これを解決するABS(CHECKSUM(NEWID()))%10 +1には、INSERTステートメントの外側/前に計算して、一度だけ計算する必要があります。何かのようなもの:

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 ;

また、このコードでは、10か国が同じ確率でテーブルに表示されないことに注意してください。最初の国(USA)は10%の確率、2番目の国は9%((100%-10%)*10%)、3番目の8.1%、((100%-19%)*10%)などになります。そのため1/e、10のいずれも選択されず、CASE式デフォルトにELSE NULLなり、エラーが発生します。(列でnullを許可し、SQLfiddleスクリプトを実行すると、確率を確認できます。)

上記によると、それを解決する別の方法は、SQL-Serverの実行方法に準拠するように式を変更することでCASEあり、10のケースすべてが同じ確率を持ちます。

    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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.