Apakah pernyataan SQL Server CASE mengevaluasi semua kondisi atau keluar pada kondisi TRUE pertama?


44

Apakah pernyataan SQL Server (2008 atau 2012, khusus) CASEmengevaluasi semua WHENkondisi atau apakah itu keluar setelah menemukan WHENklausa yang mengevaluasi ke true? Jika ia melewati seluruh rangkaian kondisi, apakah itu berarti bahwa kondisi terakhir yang mengevaluasi true menimpa apa yang dilakukan kondisi pertama yang dievaluasi ke true? Sebagai contoh:

SELECT
    CASE
        WHEN 1+1 = 2 THEN'YES'
        WHEN 1+1 = 3 THEN 'NO'
        WHEN 1+1 = 2 THEN 'NO' 
    END

Hasilnya adalah "YA" meskipun kondisi terakhir ketika harus membuatnya mengevaluasi menjadi "TIDAK". Tampaknya keluar setelah menemukan kondisi BENAR pertama. Dapatkah seseorang tolong konfirmasi jika ini masalahnya .


5
Sangat terkait erat: Apakah SQL Server membaca semua fungsi COALESCE bahkan jika argumen pertama bukan NULL? (seperti COALESCE()yang diterjemahkan ke dalam CASEekspresi.)
ypercubeᵀᴹ

Jawaban:


46

• Mengembalikan result_expression dari input_expression pertama = when_expression yang mengevaluasi ke TRUE .

Referensi http://msdn.microsoft.com/en-us/library/ms181765.aspx


Ini adalah perilaku SQL standar:

  • Sebuah CASEekspresi mengevaluasi kondisi pertama benar.

  • Jika tidak ada kondisi yang benar, itu mengevaluasi ke ELSEbagian itu.

  • Jika tidak ada kondisi sebenarnya dan tidak ada ELSEbagian, itu dievaluasi untuk NULL.


2
Saya hanya ingin memastikan bahwa jika saya memiliki 3 kondisi kasus yang semuanya akan mengevaluasi ke true, saya hanya ingin tugas yang pertama yang mengevaluasi ke benar untuk dieksekusi dan bukan yang lain 2 (walaupun mereka juga dievaluasi ke true ). Dari contoh kueri dalam pertanyaan saya, sepertinya ini masalahnya. Saya hanya ingin mengkonfirmasi. Saya juga berharap SQL membaca kondisi KASUS dari Atas ke Bawah. Terima kasih!
Juan Velez

15

SQL Server biasanya melakukan evaluasi hubung singkat untuk pernyataan KASUS ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 1 THEN 'Case 1'
      WHEN 2/0 = 1 THEN 'Case 2'
   END;

--Fails on the divide by zero.
SELECT 
   CASE 
      WHEN 1/1 = 99 THEN 'Case 1'
      WHEN 2/0 = 99 THEN 'Case 2'
   END;  

Namun ada beberapa jenis pernyataan bahwa pada SQL Server 2012 tidak melakukan hubungan pendek dengan benar. Lihat tautan dari ypercube di komentar.

Oracle selalu melakukan evaluasi hubung singkat . Lihat 11.2 Referensi Bahasa SQL . Atau bandingkan yang berikut ( SQLFiddle ):

--Does not fail on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 1 THEN 'Case 1'
    WHEN 2/0 = 1 THEN 'Case 2'
  END
FROM dual;


--Fails on the divide by zero.
SELECT
  CASE 
    WHEN 1/1 = 99 THEN 'Case 1'
    WHEN 2/0 = 99 THEN 'Case 2'
  END
FROM dual;

Tes yang sama ini tidak dapat dilakukan dengan MySQL karena mengembalikan NULL untuk pembagian dengan nol. ( SQL Fiddle )


Bagaimana dengan ini ?: SQL-Fiddle
ypercubeᵀᴹ


@ ypercube Itu perilaku yang sangat menarik. Itu mengevaluasi kode yang akan berjalan di bagian lain, tetapi tampaknya mengabaikannya tergantung pada apa yang ada KAPAN ekspresi dan apakah pembagian dengan nol di dalam MIN atau tidak. Lihat sqlfiddle.com/#!6/d41d8/4468
Leigh Riffel

@ ypercube Sekarang saya telah membaca beberapa tautan yang Anda posting, apakah Anda akan mengatakan bahwa ada cukup kasus tepi untuk mengatakan bahwa jawaban untuk apakah SQL Server melakukan evaluasi hubung singkat - biasanya?
Leigh Riffel

3
Ya, saya setuju "biasanya". Seperti yang ditunjukkan Aaron pada jawabannya, satu tes sudah cukup untuk menyangkal "KASUS selalu korsleting". Tetapi biasanya demikian.
ypercubeᵀᴹ

7

Tampaknya MS SQL Server menggunakan evaluasi hubung singkat juga.

Dalam tes berikut ini saya memiliki 3 tes. Yang pertama selalu benar, yang kedua gagal tanpa mereferensikan tabel, dan yang ketiga gagal hanya ketika data diperhitungkan.
Dalam menjalankan khusus ini kedua baris dikembalikan dengan sukses. Jika saya berkomentar KAPAN pertama, atau yang pertama dan kedua maka saya mendapatkan kegagalan.

CREATE TABLE casetest (test varchar(10))
GO
INSERT INTO casetest VALUES ('12345'),('abcdef')
GO

SELECT CASE WHEN LEN(test)>1 THEN test
        WHEN 1/0 = 1 THEN 'abc'
        WHEN CAST(test AS int) = 1 THEN 'def'
        END
FROM casetest
GO

1

jika pernyataan kasus yang digunakan dalam WHEREkondisi dan kasus pertama ketika pernyataan melibatkan evaluasi nilai kolom dari tabel, dan baris pertama dalam tabel tidak memenuhi kondisi ini, pernyataan kasus akan pergi ke kasus berikutnya saat pernyataan.

declare @tbl table(id int)
insert into @tbl values(1)
insert into @tbl values(2)
insert into @tbl values(3)

--Fails on the divide by zero.
SELECT * FROM @tbl
where  CASE 
        WHEN id = 2 THEN 1 -- first row in table will not satisfy the condition
        WHEN 2/0 = 1 THEN 1
        ELSE 0
      END =1

-- when filter the records to only who will staisfy the first case when condition, it 
will not fail on the divide by zero
SELECT * FROM @tbl
where ID=2 and -- first row in table will  satisfy the condition
  CASE 
    WHEN id = 2 THEN 1
    WHEN 2/0 = 1 THEN 1
    ELSE 0
  END =1

1

Di MySQL, ini akan keluar dari pernyataan kasus pada opsi true pertama. Jika Anda memiliki kemungkinan beberapa nilai benar, Anda ingin menempatkan jawaban pilihan sebelumnya dalam urutan.


Pertanyaannya adalah tentang SQL Server.
James Anderson
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.