T-SQL CASE子句:如何指定WHEN NULL

我写了一个类似这样的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

你知道问题出在哪里吗?

586646 次浏览
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END

WHEN部分与==进行比较,但不能真正与NULL进行比较。试一试

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

代替或COALESCE:

COALESCE(' '+last_name,'')

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

给定你的查询,你也可以这样做:

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

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

你需要显式检查null:

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

试一试:

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

这将把空格加到姓氏上,如果它为空,整个空格+姓氏将变为null,您只得到一个名字,否则您将得到一个firts+空格+姓氏。

只要设置了空字符串连接的默认设置,这就可以工作:

SET CONCAT_NULL_YIELDS_NULL ON

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

有很多解决方案,但没有一个能解释为什么最初的陈述不起作用。

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

在when之后,有一个相等的检查,它应该是真或假。

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

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

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

当你在尝试时感到沮丧时:

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并返回“as expected.”

我希望这是一个有用的替代方案。

我已经包含了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

问题是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条件(< em >不 the 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'(以及在检查not =时,不同的编程语言有不同的实现)。

但是请注意,在基本语言(即VB等)中没有'null'关键字,而是使用'Nothing'关键字,这不能用于直接比较,而是需要像SQL中那样使用' is ',然而它实际上等于它本身(当使用间接比较时)。

Jason发现了一个错误,所以这可以工作…

有人能确认其他平台版本吗?< br > SQL Server: < / p >
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

可以使用IsNull函数

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

如果其中一列为空,则会得到一个空字符

兼容Microsoft SQL Server 2008+

我试着转换到一个字符串,并测试一个零长度的字符串,它工作。

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

使用SQL Server 2012以后可用的CONCAT函数。

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

NULL不等于任何东西。case语句基本上是说当value = NULL ..
还有一些系统存储过程用您的语法写得不正确。参见sp_addpullsubscription_agent和sp_who2.
希望我知道如何通知微软这些错误,因为我无法改变系统存储的procs

我找到了解决办法。只要ISNULL CASE语句:

ISNULL(CASE x WHEN x THEN x ELSE x END, '') AS 'BLAH'

在SQL Server 2017中,微软引入了一个带有分隔符的连接函数,仅针对您的情况:

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

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

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

你可以这样用:

CASE IsNull(last_name,'') WHEN '' THEN 'Max' ELSE 'Peter' END AS Name