T-SQL CASE Clause: Cara menentukan WHEN NULL

227

Saya menulis Pernyataan T-SQL yang mirip seperti ini (yang asli terlihat berbeda tetapi saya ingin memberikan contoh mudah di sini):

SELECT first_name + 
    CASE last_name WHEN null THEN 'Max' ELSE 'Peter' END AS Name
FROM dbo.person

Pernyataan ini tidak memiliki kesalahan sintaksis apa pun, tetapi case-clause selalu memilih bagian ELSE - juga jika last_name adalah null. Tapi kenapa?

Yang ingin saya lakukan adalah menyatukan first_name dan last_name, tetapi jika last_name nol, seluruh nama menjadi nol:

SELECT first_name +
   CASE last_name WHEN null THEN '' ELSE ' ' + last_name END AS Name 
FROM dbo.person

Apakah Anda tahu di mana masalahnya?

meni
sumber

Jawaban:

369
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END
Marcelo Cantos
sumber
4
Saran @ COALESCE Luther lebih baik daripada jawaban saya. Ini sedikit kurang efisien, tetapi jauh lebih elegan.
Marcelo Cantos
Penanganannya dengan sesuatu seperti ini mungkin berguna, atau sesuatu yang serupa: COALESCE (last_name, '') Pernyataan kasus, sementara singkat, tidak terlalu dapat dipertahankan daripada COALESCE dalam pertanyaan besar. Pada akhirnya, Anda memiliki hasil yang sama. Jika Anda perlu mengoptimalkan, periksa rencana eksekusi tetapi saya belum melihat banyak perbedaan.
Anthony Mason
1
COALESCEpada dasarnya diterjemahkan secara internal menjadi CASE. Masalah dengan CASE adalah yang last_namedievaluasi dua kali dan dapat menyebabkan efek samping lain - lihat artikel yang sangat bagus ini . Untuk menyelesaikan apa yang diminta, saya lebih suka pergi dengan ISNULL(' '+ last_name, '')disebutkan dalam komentar di bawah.
miroxlav
41

Bagian WHEN dibandingkan dengan ==, tetapi Anda tidak dapat benar-benar membandingkannya dengan NULL. Mencoba

CASE WHEN last_name is NULL  THEN ... ELSE .. END

sebagai gantinya atau COALESCE:

COALESCE(' '+last_name,'')

('' + last_name adalah NULL ketika last_name adalah NULL, jadi itu harus mengembalikan '' dalam kasus itu)

Mainframe Nordik
sumber
Oke terima kasih atas informasinya dengan == di bagian SAAT. Saya tidak tahu itu. Dengan COALESCE juga berfungsi dengan baik. Belum mengira ada begitu banyak kemungkinan untuk melakukan itu.
meni
15

Ada banyak solusi tetapi tidak ada yang menjelaskan mengapa pernyataan aslinya tidak berfungsi.

CASE last_name WHEN null THEN '' ELSE ' '+last_name

Setelah kapan, ada pemeriksaan untuk kesetaraan, yang harus benar atau salah.

Jika satu atau kedua bagian dari perbandingan adalah nol, hasil perbandingan tersebut akan DIKETAHUI, yang diperlakukan sebagai false dalam struktur kasus. Lihat: https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

Untuk menghindari ini, Coalesce adalah cara terbaik.

kamahl
sumber
11

Dengan kueri Anda, Anda juga dapat melakukan ini:

SELECT first_name + ' ' + ISNULL(last_name, '') AS Name FROM dbo.person
Ian Jacobs
sumber
2
Ini menambahkan ruang berlebihan ketika last_name adalah nol, yang mana OP berusaha untuk menghindari.
Marcelo Cantos
6
Lebih baik digunakan ISNULL(' '+ last_name, '')untuk mencegah ruang redundan.
Prutswonder
Ya menyadarinya setelah saya diposting. Kupikir aku akan meninggalkannya karena itu menyelesaikan bagian yang sedang bermasalah dengannya.
Ian Jacobs
7

Masalahnya adalah bahwa null tidak dianggap sama dengan dirinya sendiri, maka klausa tidak pernah cocok.

Anda perlu memeriksa null secara eksplisit:

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name
b0fh
sumber
5

mencoba:

SELECT first_name + ISNULL(' '+last_name, '') AS Name FROM dbo.person

Ini menambahkan spasi ke nama belakang, jika itu nol, seluruh ruang + nama belakang pergi ke NULL dan Anda hanya mendapatkan nama depan, jika tidak, Anda akan mendapatkan firts + spasi + nama belakang.

ini akan berfungsi selama pengaturan default untuk rangkaian dengan string nol diatur:

SET CONCAT_NULL_YIELDS_NULL ON 

ini seharusnya tidak menjadi perhatian karena OFFmode akan hilang dalam versi SQl Server yang akan datang

KM.
sumber
4

Masalahnya adalah bahwa NULL tidak dianggap sama dengan apa pun bahkan tidak dengan dirinya sendiri, tetapi bagian yang aneh adalah bahwa itu juga tidak sama dengan dirinya sendiri.

Pertimbangkan pernyataan berikut (yang ilegal BTW di SQL Server T-SQL tetapi valid dalam My-SQL, namun ini adalah apa yang ANSI tetapkan untuk null, dan dapat diverifikasi bahkan dalam SQL Server dengan menggunakan pernyataan kasus, dll.)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

Jadi tidak ada jawaban benar / salah untuk pertanyaan, sebaliknya jawabannya juga nol.

Ini memiliki banyak implikasi, misalnya dalam

  1. Pernyataan CASE, di mana setiap nilai null akan selalu menggunakan klausa ELSE kecuali jika Anda menggunakan eksplisit KETIKA IS kondisi NULL ( TIDAK yang WHEN NULLkondisi )
  2. Rangkaian string, sebagai
    SELECT a + NULL -- Results in NULL
  3. Dalam klausa WHERE IN atau WHERE NOT IN, seolah-olah Anda ingin hasil yang benar, pastikan dalam sub-kueri yang berkorelasi untuk memfilter nilai null apa pun.

Seseorang dapat mengesampingkan perilaku ini dalam SQL Server dengan menentukan SET ANSI_NULLS OFF, namun ini TIDAK dianjurkan dan tidak boleh dilakukan karena dapat menyebabkan banyak masalah, hanya karena penyimpangan standar.

(Sebagai catatan, di My-SQL ada opsi untuk menggunakan operator khusus <=>untuk perbandingan nol.)

Sebagai perbandingan, dalam bahasa pemrograman umum null diperlakukan sebagai nilai reguler dan sama dengan dirinya sendiri, namun itu adalah nilai NAN yang juga tidak sama dengan dirinya sendiri, tetapi setidaknya mengembalikan 'salah' ketika membandingkannya dengan dirinya sendiri, (dan ketika memeriksa tidak sama dengan bahasa pemrograman yang berbeda, memiliki implementasi yang berbeda).

Perhatikan bahwa dalam bahasa-bahasa Basic (mis. VB dll.) Tidak ada kata kunci 'null' dan sebaliknya orang menggunakan kata kunci 'Nothing', yang tidak dapat digunakan dalam perbandingan langsung dan sebagai gantinya orang perlu menggunakan 'IS' seperti dalam SQL, namun sebenarnya sama dengan dirinya sendiri (saat menggunakan perbandingan tidak langsung).

halo yoel
sumber
1
"Bagian yang aneh adalah itu juga tidak sama dengan dirinya sendiri." => ini tidak aneh mengingat null dalam SQL memiliki arti 'tidak diketahui'. Sesuatu yang tidak diketahui, kemungkinan besar tidak sama dengan sesuatu yang tidak dikenal.
JDC
1
CASE  
    WHEN last_name IS null THEN '' 
    ELSE ' ' + last_name 
END
Linda
sumber
1

Ketika Anda merasa frustrasi mencoba ini:

CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END

Coba yang ini sebagai gantinya:

CASE LEN(ISNULL(last_Name,''))
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

LEN(ISNULL(last_Name,''))mengukur jumlah karakter di kolom itu, yang akan menjadi nol apakah itu kosong, atau NULL, oleh karena itu WHEN 0 THENakan mengevaluasi ke true dan mengembalikan '' seperti yang diharapkan.

Saya harap ini adalah alternatif yang bermanfaat.

Saya telah memasukkan test case ini untuk sql server 2008 dan di atasnya:

DECLARE @last_Name varchar(50) = NULL

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName

SET @last_Name = 'LastName'

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName
Chef Slagle
sumber
2
Apakah Anda yakin itu berhasil? Sebagian besar fungsi mengembalikan NULL ketika diberi input NULL dan pengujian saya mengonfirmasi bahwa itu juga berlaku untuk LEN () yaitu, LEN (NULL) mengembalikan NULL, bukan 0.
Jason Musgrove
Pokechu22 benar, dan ini adalah skrip yang diperbaiki: KASUS LEN (ISNULL (last_Name, '')) KETIKA 0 LALU '' LAIN '' + last_name AKHIR SEBAGAIlastName
Chef Slagle
0

Jason mendapat kesalahan, jadi ini berfungsi ...

Adakah yang bisa mengkonfirmasi versi platform lainnya?
SQL Server:

SELECT
CASE LEN(ISNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

MySQL:

SELECT
CASE LENGTH(IFNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

Peramal:

SELECT
CASE LENGTH(NVL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName
Chef Slagle
sumber
0

Anda dapat menggunakan fungsi IsNull

select 
    isnull(rtrim(ltrim([FirstName]))+' ','') +
    isnull(rtrim(ltrim([SecondName]))+' ','') +
    isnull(rtrim(ltrim([Surname]))+' ','') +
    isnull(rtrim(ltrim([SecondSurname])),'')
from TableDat

jika satu kolom nol Anda akan mendapatkan char kosong

Kompatibel dengan Microsoft SQL Server 2008+

Molem
sumber
0

Gunakan fungsi CONCAT yang tersedia di SQL Server 2012 dan seterusnya.

SELECT CONCAT([FirstName], ' , ' , [LastName]) FROM YOURTABLE
TSQL
sumber
0

Saya mencoba casting ke string dan menguji string dengan panjang nol dan berhasil.

CASE 
   WHEN LEN(CAST(field_value AS VARCHAR(MAX))) = 0 THEN 
       DO THIS
END AS field 
pengguna2463829
sumber
0

NULL tidak sama dengan apa pun. Pernyataan kasus pada dasarnya mengatakan ketika nilai = NULL .. itu tidak akan pernah mengenai.
Ada juga beberapa prosedur tersimpan sistem yang ditulis secara salah dengan sintaks Anda. Lihat sp_addpullsubscription_agent dan sp_who2.
Seandainya saya tahu cara memberi tahu Microsoft tentang kesalahan itu karena saya tidak dapat mengubah sistem yang disimpan procs.

Joshua Walker
sumber