T-SQL CASE yan tümcesi: WHEN NULL belirtme


228

Buna benzer bir T-SQL Bildirimi yazdım (orijinali farklı görünüyor ama burada kolay bir örnek vermek istiyorum):

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

Bu Bildirimde herhangi bir sözdizimi hatası yoktur, ancak büyük / küçük harf her zaman ELSE bölümünü seçer - son_adı boşsa da. Ama neden?

Ne yapmak istiyorum first_name ve last_name birleştirmek, ancak last_name null ise tüm adı null olur:

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

Sorunun nerede olduğunu biliyor musun?

Yanıtlar:


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

4
@ Luther'in COALESCE önerisi cevabımdan daha iyi. Sınırlı olarak daha az verimlidir, ancak çok daha zariftir.
Marcelo Cantos

Bunun gibi bir şeyle ya da benzeri bir şeyle kullanılması yararlı olabilir: COALESCE (last_name, '') Vaka ifadesi, özlü olmasına rağmen, büyük sorgularda COALESCE'dan daha az bakım yapılabilir. Sonunda, aynı sonuca sahipsiniz. Optimize etmeniz gerekiyorsa, yürütme planlarını kontrol edin, ancak çok fazla fark görmedim.
Anthony Mason

1
COALESCEtemelde dahili olarak çevirir CASE. CASE ile ilgili sorun last_nameiki kez değerlendirilmesidir ve diğer yan etkilere yol açabilir - bu mükemmel makaleye bakın . İsteneni çözmek için, ben daha çok giderdim ISNULL(' '+ last_name, '')belirtilen yorumun altında.
miroxlav

41

WHEN kısmı == ile karşılaştırılır, ancak NULL ile gerçekten kıyaslayamazsınız. Deneyin

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

yerine veya COALESCE:

COALESCE(' '+last_name,'')

('' + last_name, last_name NULL olduğunda NULL olur, bu durumda geri dönmelidir '')


Tamam, NE ZAMAN bölümünde == olan bilgiler için teşekkür ederim. Bunu bilmiyordum. COALESCE ile iyi çalışır. Bunu yapmak için çok fazla olasılık olduğunu düşünmemiştim.
meni

15

Çok sayıda çözüm var, ancak hiçbiri orijinal ifadenin neden çalışmadığını kapsamıyor.

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

Ne zaman sonra, doğru veya yanlış olması gereken bir eşitlik kontrolü vardır.

Bir karşılaştırmanın bir veya her iki kısmı null olursa, karşılaştırmanın sonucu bir vaka yapısında false gibi davranılan BİLİNMEYEN sonuç olacaktır. Bkz. Https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

Bundan kaçınmak için Coalesce en iyi yoldur.


11

Sorgunuz verildiğinde bunu da yapabilirsiniz:

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

2
Bu, last_name null olduğunda gereksiz bir alan ekler, bu da OP'nin kaçınmaya çalıştığı şeydir.
Marcelo Cantos

6
ISNULL(' '+ last_name, '')Gereksiz alanı önlemek için daha iyi kullanın .
Prutswonder

Evet, gönderdikten sonra fark ettim. Sorun yaşadığı kısmı çözdüğü için bırakacağımı düşündüm.
Ian Jacobs

7

Sorun şu ki, null kendiliğinden eşit kabul edilmez, dolayısıyla madde hiçbir zaman eşleşmez.

Açık olarak null olup olmadığını kontrol etmeniz gerekir:

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name

5

Deneyin:

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

Bu, soyadına boşluk ekler, eğer boşsa, tüm boşluk + soyadı NULL olur ve yalnızca bir ad alırsınız, aksi takdirde bir firts + boşluk + soyadı alırsınız.

bu, boş dizelerle birleştirme için varsayılan ayar ayarlandığı sürece çalışır:

SET CONCAT_NULL_YIELDS_NULL ON 

OFFmod, SQl Server'ın gelecekteki sürümlerinde kullanımdan kaldırıldığı için bu bir endişe kaynağı olmamalı


4

Sorun şu ki, NULL kendisi için bile hiçbir şeye eşit kabul edilmez, ama garip olan kısım da kendine eşit değildir .

Aşağıdaki ifadeleri göz önünde bulundurun (SQL Server T-SQL'de BTW yasadışıdır, ancak My-SQL'de geçerlidir, ancak ANSI null için tanımladığı şey budur ve SQL Server'da vaka ifadeleri vb. Kullanılarak doğrulanabilir)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

Dolayısıyla soruya doğru / yanlış cevap yoktur, bunun yerine cevap da boştur.

Bunun birçok etkisi vardır, örneğin

  1. Açıkça kullanmadığınız sürece herhangi boş değeri her zaman BAŞKA maddesini kullanacak olan VAKA ifadeleri, ZAMAN BOŞ koşulu (IS DEĞİL koşul )WHEN NULL
  2. Dize birleştirme, as
    SELECT a + NULL -- Results in NULL
  3. WHERE IN veya WHERE NOT IN yan tümcesinde, doğru sonuçlar istiyormuş gibi ilişkili alt sorguda boş değerleri filtrelediğinizden emin olun.

Bir belirterek SQL Server'da bu davranışı geçersiz kılabilir SET ANSI_NULLS OFF, ancak bu tavsiye DEĞİLDİR ve standart sapması nedeniyle birçok soruna neden olabileceği için yapılmamalıdır.

(Yan not olarak, My-SQL'de <=>boş karşılaştırma için özel bir işleç kullanma seçeneği vardır .)

Buna karşılık, genel olarak programlama dillerinde boş değer işleme tabi tutulur ve kendisine eşittir, ancak aynı zamanda kendisine eşit olmayan NAN değeridir, ancak en azından kendisiyle karşılaştırıldığında 'yanlış' döndürür (ve eşit olmadığında kontrol ederken farklı programlama dilleri farklı uygulamalara sahiptir).

Bununla birlikte, Temel dillerde (yani VB vb.) 'Null' anahtar kelimesi olmadığını ve bunun yerine doğrudan karşılaştırmada kullanılamayan ve bunun yerine SQL'deki gibi 'IS' kullanması gereken 'Nothing' anahtar kelimesini kullandığını, bununla birlikte aslında kendine eşittir (dolaylı karşılaştırmalar kullanılırken).


1
"Garip olan kısım da kendine eşit değil." => SQL'de null değerinin 'bilinmeyen' anlamına geldiği düşünüldüğünde bu garip değildir. Bilinmeyen bir şey, büyük olasılıkla bilinmeyen başka bir şeyle aynı değildir.
JDC

1
CASE  
    WHEN last_name IS null THEN '' 
    ELSE ' ' + last_name 
END

1

Bunu denerken hayal kırıklığına uğradığınızda:

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

Bunun yerine şunu deneyin:

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

LEN(ISNULL(last_Name,''))bu sütundaki karakter sayısını ölçer; boş olup olmadığı sıfır olur veya NULL olur, bu nedenle WHEN 0 THENtrue olarak değerlendirilir ve '' beklendiği gibi döndürülür.

Umarım bu faydalı bir alternatiftir.

Sql server 2008 ve üstü için bu test durumunu ekledim:

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

2
Bunun işe yaradığından emin misin? NULL girdi verildiğinde çoğu işlev NULL döndürür ve testlerim bunun LEN () için de geçerli olduğunu doğrular, yani LEN (NULL) 0 değil NULL döndürür.
Jason Musgrove

Pokechu22 doğru ve bu düzeltilmiş komut dosyasıdır: CASE LEN (ISNULL (last_Name, '')) 0 SONRA '' BAŞKA '' + soyad SONRAKİ newlastName
Chef Slagle 21

0

Jason bir hata yakaladı, bu yüzden çalışıyor ...

Herkes diğer platform sürümlerini onaylayabilir mi?
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

Oracle:

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

0

IsNull işlevini kullanabilirsiniz

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

bir sütun boşsa, boş bir karakter alırsınız

Microsoft SQL Server 2008+ ile uyumlu


0

SQL Server 2012'den sonraki CONCAT işlevini kullanın.

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

0

Bir dize döküm ve sıfır uzunlukta bir dize için test çalıştı ve çalıştı.

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

0

NULL hiçbir şeye eşit değildir. Case deyimi temelde = NULL .. hiçbir zaman vurmayacak diyor.
Ayrıca sözdiziminizle yanlış yazılmış birkaç sistem saklı yordamı vardır. Bkz. Sp_addpullsubscription_agent ve sp_who2.
Keşke sistemde saklanan işlemleri değiştiremediğim için bu hataları Microsoft'a nasıl bildireceğimi bilseydim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.