T-SQL CASE句:WHEN NULLを指定する方法


227

私は次のようなT-SQLステートメントを記述しました(元のステートメントは異なって見えますが、ここで簡単な例を挙げたいと思います)。

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

このステートメントには構文エラーはありませんが、last_nameがnullの場合も、case-clauseは常にELSE-partを選択します。しかし、なぜ?

私がやりたいのは、first_nameとlast_nameを結合することですが、last_nameがnullの場合、名前全体がnullになります。

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

問題がどこにあるか知っていますか?

回答:


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

4
@LutherのCOALESCEの提案は私の回答よりも優れています。効率はやや劣りますが、はるかにエレガントです。
Marcelo Cantos 2010

COALESCE(last_name、 '')Caseステートメントは簡潔ですが、大規模なクエリではCOALESCEほど保守性が低くなります。最終的には、同じ結果になります。最適化する必要がある場合は、実行計画を確認してください。ただし、ほとんど違いはありません。
アンソニーメイソン

1
COALESCE基本的に内部的にに変換されCASEます。CASEの問題は、last_name2回評価され、他の副作用につながる可能性があることです。この優れた記事を参照してください。尋ねられたことを解決するために、私はむしろ以下のコメントISNULL(' '+ last_name, '')言及されたものに行きたいと思います。
miroxlav

41

WHENの部分は==と比較されますが、実際にはNULLと比較することはできません。試す

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

代わりに、またはCOALESCE:

COALESCE(' '+last_name,'')

(last 'nameがNULLの場合、' '+ last_nameはNULLなので、その場合は' 'を返す必要があります)


WHENの部分に==が付いた情報をありがとうございます。知らなかった。COALESCEを使用すると、正常に機能します。それをする可能性がそんなにあるとは考えていませんでした。
meni

15

解決策はたくさんありますが、元のステートメントが機能しない理由はカバーされていません。

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

whenの後に、等しいかどうかのチェックがあり、trueまたはfalseでなければなりません。

比較の一方または両方の部分がnullの場合、比較の結果はUNKNOWNになり、ケース構造ではfalseのように扱われます。参照:https : //www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

これを回避するには、コアレスが最善の方法です。


11

あなたのクエリを考えると、これを行うこともできます:

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

2
これにより、last_nameがnullの場合に冗長スペースが追加されます。これは、OPが回避しようとしていたことです。
Marcelo Cantos

6
ISNULL(' '+ last_name, '')余分なスペースを防ぐために使用してください。
Prutswonder 2010

うん、投稿してから気づいた。彼が問題を抱えていた部分を解決したので、私はそれを残しておくと考えました。
イアンジェイコブス

7

問題は、nullがそれ自体と等しいとは見なされないため、句が一致しないことです。

nullを明示的に確認する必要があります。

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

5

試してください:

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

これにより、姓にスペースが追加されます。nullの場合、スペース+ラストネーム全体がNULLになり、名のみが取得されます。それ以外の場合、最初+スペース+ラストネームが取得されます。

これは、null文字列との連結のデフォルト設定が設定されている限り機能します。

SET CONCAT_NULL_YIELDS_NULL ON 

OFFSQl Serverの将来のバージョンではモードがなくなるので、これは問題になりません。


4

問題は、NULLはそれ自体とは等しくないものと見なされないことですが、奇妙な点は、それ自体と等しくないことです。

次のステートメントを検討してください(SQL Server T-SQLではBTWは不正ですが、My-SQLでは有効ですが、これはANSIがnullに対して定義しているものであり、SQLステートメントでもcaseステートメントなどを使用して確認できます)。

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

したがって、質問に対する真/偽の答えはありませんが、代わりに答えもnullです。

これには、たとえば次のような多くの意味があります。

  1. あなたが明示的に使用しない限り、すべてのヌル値は常にELSE句を使用しますするCASEステートメントは、WHEN NULL条件(IS NOT条件WHEN NULL
  2. 文字列連結
    SELECT a + NULL -- Results in NULL
  3. WHERE IN句またはWHERE NOT IN句では、正しい結果が必要であるかのように、相関サブクエリでnull値を除外するようにしてください。

一つは、指定することで、SQL Serverでこの動作を無効にすることができますSET ANSI_NULLS OFFが、これはされて、NOT推奨、それは単に標準の偏差ので、多くの問題を引き起こす可能性がありますように行うべきではありません。

(補足として、My-SQLには<=>null比較に特別な演算子を使用するオプションがあります。)

比較すると、一般的なプログラミング言語では、nullは通常の値として扱われ、それ自体と等しくなりますが、これもNAN値であり、これもそれ自体とは等しくありませんが、それ自体と比較すると、少なくとも「false」を返します(そして等しくないかどうかをチェックするとき、異なるプログラミング言語は異なる実装を持っています)。

ただし、基本言語(VBなど)には「null」キーワードはなく、代わりに「Nothing」キーワードを使用します。これは直接比較では使用できず、SQLのように「IS」を使用する必要があります。ただし、実際にはそれ自体と同じです(間接比較を使用する場合)。


1
「奇妙な点は、それ自体と同じではないことです。」=> SQLのnullには「不明」という意味があるため、これは奇妙なことではありません。未知の何かは、おそらく未知の何かと同じではありません。
JDC、


1

これを試してイライラしたとき:

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

代わりにこれを試してください:

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

LEN(ISNULL(last_Name,''))その列の文字数を測定します。これは、空であってもNULLであってもゼロであるためWHEN 0 THEN、trueと評価され、期待どおりに ''を返します。

これが役立つ代替案であることを願っています。

このSQL Server 2008以降のテストケースを含めました。

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
うまくいきますか?また、(LENの本当のNULL入力と私のテスト確認を与えられたとき、ほとんどの関数はすなわち、LEN(NULL)はNULLではなく、0を返します)NULLを返す
ジェイソンMusgrove

Pokechu22は正しく、これは修正されたスクリプトです:CASE LEN(ISNULL(last_Name、 ''))WHEN 0 THEN '' ELSE '' + last_name END AS newlastName
Chef Slagle

0

ジェイソンはエラーをキャッチしたので、これは機能します...

誰か他のプラットフォームのバージョンを確認できますか?
SQLサーバー:

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関数を使用できます

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

1つの列がnullの場合、空の文字を取得します

Microsoft SQL Server 2008以降と互換性があります


0

SQL Server 2012以降で使用可能なCONCAT関数を使用します。

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

0

文字列にキャストして、長さゼロの文字列をテストしてみましたが、うまくいきました。

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

0

NULLは何にも等しくありません。ケースステートメントは、基本的に値= NULL ..の場合はヒットしないことを示しています。
構文で誤って記述されているシステムストアドプロシージャもいくつかあります。sp_addpullsubscription_agentおよびsp_who2を参照してください。
システムストアドプロシージャを変更できないため、これらの間違いをマイクロソフトに通知する方法を知っていればよいのですが。

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