243

我写了一个类似这样的 T-SQL 语句(原来的看起来不同,但我想在这里举一个简单的例子):

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

此语句没有任何语法错误,但 case-clause 始终选择 ELSE 部分 - 即使 last_name 为空。但为什么?

我想要做的是联合 first_name 和 last_name,但如果 last_name 为空,则整个名称变为空:

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

你知道问题出在哪里吗?

4

16 回答 16

394
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END
于 2010-07-13T13:34:31.443 回答
46

WHEN 部分与 == 进行比较,但您无法真正与 NULL 进行比较。尝试

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

相反或合并:

COALESCE(' '+last_name,'')

(' '+last_name 当 last_name 为 NULL 时为 NULL,所以在这种情况下它应该返回 '')

于 2010-07-13T13:36:57.120 回答
17

有很多解决方案,但没有一个涵盖为什么原始语句不起作用。

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

在 when 之后,有一个相等性检查,它应该是 true 或 false。

如果比较的一个或两个部分为空,则比较结果将为 UNKNOWN,在案例结构中被视为 false。请参阅:https ://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

为了避免这种情况,Coalesce 是最好的方法。

于 2010-07-14T07:09:28.263 回答
13

鉴于您的查询,您也可以这样做:

SELECT first_name + ' ' + ISNULL(last_name, '') AS Name FROM dbo.person
于 2010-07-13T13:37:31.377 回答
8

问题是 null 不被认为等于它自己,因此该子句永远不会匹配。

您需要明确检查 null :

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name
于 2010-07-13T13:37:40.297 回答
5

尝试:

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

这会将空格添加到姓氏,如果它为空,则整个空格+姓氏将变为 NULL,并且您只会得到一个名字,否则您会得到一个名字+空格+姓氏。

只要设置了与空字符串连接的默认设置,这将起作用:

SET CONCAT_NULL_YIELDS_NULL ON 

这不应该是一个问题,因为该OFF模式将在 SQl Server 的未来版本中消失

于 2010-07-13T14:51:54.887 回答
5

问题是 NULL 被认为不等于任何东西,甚至不等于它自己,但奇怪的是它也不等于它自己。

考虑以下语句(顺便说一句,这在 SQL Server T-SQL 中是非法的,但在 My-SQL 中有效,但是这是 ANSI 为 null 定义的,甚至可以在 SQL Server 中通过使用 case 语句等进行验证)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

所以这个问题没有真/假答案,答案也是空的。

这有很多含义,例如

  1. CASE 语句,其中任何空值将始终使用 ELSE 子句,除非您明确使用 WHEN IS NULL 条件不是条件WHEN NULL
  2. 字符串连接,如
    SELECT a + NULL -- Results in NULL
  3. 在 WHERE IN 或 WHERE NOT IN 子句中,如果您想要正确的结果,请确保在相关子查询中过滤掉任何空值。

可以通过指定覆盖 SQL Server 中的这种行为SET ANSI_NULLS OFF,但是建议这样做,也不应该这样做,因为它可能会导致许多问题,仅仅是因为标准的偏差。

(附带说明一下,在 My-SQL 中有一个选项可以使用特殊运算符<=>进行空值比较。)

相比之下,在一般编程语言中,null 被视为常规值并且等于自身,但是它是 NAN 值,它也不等于自身,但至少在与自身比较时返回“false”,(并且当检查不等于时,不同的编程语言有不同的实现)。

但是请注意,在 Basic 语言(即 VB 等)中,没有“null”关键字,而是使用“Nothing”关键字,它不能用于直接比较,而是需要使用 SQL 中的“IS”,然而它实际上等于它自己(当使用间接比较时)。

于 2015-04-16T01:01:57.637 回答
3

找到了解决方案。只是声明ISNULLCASE

ISNULL(CASE x WHEN x THEN x ELSE x END, '') AS 'BLAH'
于 2020-07-17T19:01:11.817 回答
1
CASE  
    WHEN last_name IS null THEN '' 
    ELSE ' ' + last_name 
END
于 2012-11-19T15:34:13.483 回答
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
于 2014-09-18T23:37:03.347 回答
1

杰森发现了一个错误,所以这有效......

谁能确认其他平台版本?
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

甲骨文:

SELECT
CASE LENGTH(NVL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName
于 2015-10-29T15:43:45.513 回答
0

您可以使用 IsNull 函数

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

如果一列为空,您将得到一个空字符

与 Microsoft SQL Server 2008+ 兼容

于 2017-05-19T14:25:28.213 回答
0

我尝试转换为一个字符串并测试一个零长度的字符串并且它有效。

CASE 
   WHEN LEN(CAST(field_value AS VARCHAR(MAX))) = 0 THEN 
       DO THIS
END AS field 
于 2017-06-22T20:11:43.220 回答
0

使用 SQL Server 2012 及更高版本中提供的 CONCAT 函数。

SELECT CONCAT([FirstName], ' , ' , [LastName]) FROM YOURTABLE
于 2017-12-05T04:39:42.500 回答
0

NULL 不等于任何东西。case 语句基本上是说当 value = NULL .. 它永远不会命中。
还有几个系统存储过程用您的语法错误地编写。请参见 sp_addpullsubscription_agent 和 sp_who2。
希望我知道如何将这些错误通知 Microsoft,因为我无法更改系统存储的过程。

于 2018-03-08T20:29:54.720 回答
0

在 SQL Server 2017 中,Microsoft 针对您的情况引入了 Concatenate With Separator 函数:

SELECT CONCAT_WS(' ', first_name, last_name) FROM dbo.person

CONCAT_WS 跳过 NULL 值,但不跳过空字符串。

有趣的是,MySQL 在十多年前就引入了 CONCAT_WS。

于 2021-05-22T16:24:55.763 回答