Nilai Null dalam pernyataan KASUS


8

Saya bermain-main dengan beberapa hal dalam SSMS untuk belajar sedikit lebih banyak ketika saya belajar untuk ujian 70-461 saya dan saya menemukan sedikit gangguan. Saya mencoba membuat tabel untuk bermain-main sehingga saya tidak perlu mengubah / menghapus tabel yang sudah dibuat di database AdventureWorks atau TSQL2012. Saya telah membuat tabel temp untuk menguji kode saya sebelum saya benar-benar membuat tabel untuk bermain dan ini adalah kode yang saya gunakan untuk memasukkan nilai ke dalam tabel saya:

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;

Masalah yang saya alami adalah saya terus mendapatkan pesan kesalahan yang mengatakan "Tidak dapat memasukkan nilai NULL ke kolom 'Negara', tabel 'tempdb.dbo. # TestEmployeeCountry" Alasannya adalah karena saya mengatur kolom Negara disetel ke TIDAK NULL, dan kode saya tidak berfungsi untuk beberapa sisipan, masalahnya adalah saya secara acak mendapatkan nilai NULL dari pernyataan kasus saya.

Saya tahu bahwa untuk memperbaiki ini saya dapat dengan mudah menambahkan baris lain yang mengatakan "DEFAULT xxxxxx" namun saya ingin mengerti apa yang sedang terjadi karena berdasarkan apa yang saya lihat saya tidak harus melakukan itu, bukan? Saya pikir saya menulis pernyataan kasus saya dengan benar, memberi saya angka antara 1-10 saja dan setelah menguji hanya pernyataan pilih spesifik lebih dari 1000 percobaan, saya selalu mendapatkan angka acak antara 1-10, tidak ada yang lebih besar atau lebih kecil. Adakah yang bisa membantu saya memahami mengapa kode ini mencoba memasukkan nilai NULL ke dalam kolom itu?

Jawaban:


8

Mengapa ini terjadi sudah dijawab oleh @PaulWhite dalam pertanyaan SO: Bagaimana ungkapan KASUS ini mencapai klausa ELSE?

Untuk mengatasinya, Anda harus menghitung ABS(CHECKSUM(NEWID()))%10 +1luar / sebelum INSERTpernyataan sehingga dihitung sekali. Sesuatu seperti:

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 ;

Juga perhatikan bahwa dengan kode Anda, 10 negara tidak akan ditempatkan dalam tabel dengan probabilitas yang sama! Negara pertama ( USA) akan memiliki peluang 10%, yang kedua akan memiliki 9% ( (100%-10%)*10%), yang ketiga 8,1%, ( (100%-19%)*10%), dll. Itu meninggalkan peluang yang tidak begitu kecil (sekitar 1/e) sehingga tidak ada dari 10 yang dipilih dan CASEekspresi pergi ke default ELSE NULLdan Anda mendapatkan kesalahan. (Anda dapat memeriksa probabilitas jika Anda mengizinkan nol di kolom dan menjalankan skrip SQLfiddle .)

Menurut hal di atas, cara lain untuk menyelesaikannya adalah dengan mengubah ekspresi untuk mematuhi bagaimana SQL-Server mengeksekusi CASEdan semua 10 kasus memiliki probabilitas yang sama:

    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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.