SQL Server中的字符串拼接与null值

100

我正在创建一个由多个字段计算的列,其中一些字段可能为空。

问题在于,如果其中任何一个字段为空,则整个计算列都将为空。根据Microsoft的文档,我了解到这是预期的,并且可以通过设置SET CONCAT_NULL_YIELDS_NULL来关闭此功能。但是,我不想更改此默认行为,因为我不知道它对SQL Server的其他部分的影响。

有没有办法只检查一个列是否为空,如果非空则在计算列公式中只追加其内容呢?


3
当问题被提出时,被接受的答案是正确的,但对于所有使用SQL Server 2012及更高版本的人(现在应该是所有人),@Martin-Smith的答案是最好的,因为它可以自动处理空值。 - Dowlers
这是默认值确实有点奇怪,我想不出任何场景为什么要返回 null,你有什么建议吗? - Paul McCarthy
10个回答

161
你可以使用 ISNULL(....)
SET @Concatenated = ISNULL(@Column1, '') + ISNULL(@Column2, '')
如果列/表达式的值确实为NULL,则将使用指定的第二个值(这里为空字符串)。

28
“Coalesce”是ANSI标准函数名称,但“ISNULL”的拼写更容易。 - Philip Kelley
1
而且在SQL Server上,ISNULL似乎更快 - 因此,如果您想在将字符串连接到计算列的函数中使用它,则可以放弃ANSI标准并选择速度(请参见Adam Machanic:http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/performance-isnull-vs-coalesce.aspx)。 - marc_s
刚刚使用了这个Isnull()查询,它对我很有帮助,因为我正在将值连接在一起,如果其中一个为空,那么所有的值都会变成空。 - Sizons
1
使用 ISNULL() 是一个不错的解决方案,但从 SQL Server 2012 开始,您也可以使用 CONCAT 函数来获得相同的结果:CONCAT(@Column1, @Column2) - Muhammad Musavi
@Mohammadlm71:正确- 但是这个答案是2010年的,那时SQL Server 2012还不存在;如果你仍在使用2005、2008或2008 R2,则应该采用这种方式。 - marc_s
2
值得注意的是,如果您想将null替换为除空字符串之外的其他内容,例如IsNull(@Column1, 'NULLVALUE'),则使用IsNull函数时,替换字符串的长度受其替换的列的长度限制,而使用Coalesce函数则没有此限制。 - Jamie

78

从 SQL Server 2012 开始,使用 CONCAT 函数变得更加容易。

该函数将 NULL 视为空字符串。

DECLARE @Column1 VARCHAR(50) = 'Foo',
        @Column2 VARCHAR(50) = NULL,
        @Column3 VARCHAR(50) = 'Bar';


SELECT CONCAT(@Column1,@Column2,@Column3); /*Returns FooBar*/

对于旧版本,您会收到“'CONCAT'不是已知的内置函数名称”的错误提示,因此请使用COALESCE。 - Savage
5
@Savage - COALESCE不能起到合并字符串的作用,它只会返回第一个非空参数。 - codeulike

35

使用COALESCE函数。将your_column替换为COALESCE(your_column, '')。这样会返回空字符串而不是NULL。


OP想要将字符串连接在一起,COALESCE不能做到这一点。 - codeulike
@codeulike,您可以使用此方法将null替换为空字符串,然后将其与旧的字符串连接运算符(+)的结果一起使用 - 就像接受的答案使用ISNULL一样。 - Martin Smith

16

您也可以使用 CASE - 我下面的代码检查 null 值和空字符串,并只有在后跟值时才添加分隔符:

SELECT OrganisationName, 
'Address' = 
CASE WHEN Addr1 IS NULL OR Addr1 = '' THEN '' ELSE Addr1 END + 
CASE WHEN Addr2 IS NULL OR Addr2 = '' THEN '' ELSE ', ' + Addr2 END + 
CASE WHEN Addr3 IS NULL OR Addr3 = '' THEN '' ELSE ', ' + Addr3 END + 
CASE WHEN County IS NULL OR County = '' THEN '' ELSE ', ' + County END 
FROM Organisations 

我标记了这个,但现在我认为它存在问题:如果第一个字符串Addr1为空或者为NULL,并且第二个、第三个或第四个字符串Addr2、Addr3或County不为空,则地址将以一个不必要的逗号开头。很遗憾,我喜欢这个想法和清晰度 :( - Zeek2
...但你可以使用TRIM()来解决这个问题(删除前导和尾随逗号)。例如,我正在使用SQL变量并使用类似以下的语句:SET @strAddress = TRIM(',' FROM @strAddress) - Zeek2

12

使用

SET CONCAT_NULL_YIELDS_NULL  OFF 

将 null 值连接到字符串中不会导致 null。

请注意,这是一个弃用的选项,请避免使用。 有关详细信息,请参见文档


10

如果有人需要帮助添加字符串之间的分隔符,取决于字段是否为 NULL ,我只是想做出贡献。

所以在创建一个单行地址的例子中

Address1Address2Address3CityPostCode

在我的情况下,我有以下计算列似乎可以按照我想要的方式工作:

case 
    when [Address1] IS NOT NULL 
    then (((          [Address1]      + 
          isnull(', '+[Address2],'')) +
          isnull(', '+[Address3],'')) +
          isnull(', '+[City]    ,'')) +
          isnull(', '+[PostCode],'')  
end

希望这能帮助到某些人!


那里有相当多的冗余嵌套括号可以被移除。另一个提示是,如果address1为空,则整个表达式将计算为null(尽管有case语句会引起注意,这种情况可能发生)。 - Alternator

7

ISNULL(ColumnName, '')


2

我也遇到了很多问题。无法使用上面的示例解决问题,但是以下内容对我有用:

Replace(rtrim(ltrim(ISNULL(Flat_no, '') + 
' ' + ISNULL(House_no, '') + 
' ' + ISNULL(Street, '') + 
' ' + ISNULL(Town, '') + 
' ' + ISNULL(City, ''))),'  ',' ')

Replace函数可以将由单个空格相连而没有任何间隔的双空格纠正为单个空格。 r/ltrim 函数可去除两端的任何空格。


0

在 Sql Server 中:

insert into Table_Name(PersonName,PersonEmail) values(NULL,'xyz@xyz.com')

PersonName is varchar(50), NULL is not a string, because we are not passing with in single codes, so it treat as NULL.

代码后端:

string name = (txtName.Text=="")? NULL : "'"+ txtName.Text +"'";
string email = txtEmail.Text;

insert into Table_Name(PersonName,PersonEmail) values(name,'"+email+"')

-1

这个例子将帮助您在创建插入语句时处理各种类型

select 
'insert into doc(Id, CDate, Str, Code, Price, Tag )' + 
'values(' +
      '''' + convert(nvarchar(50), Id) + ''',' -- uniqueidentifier
    + '''' + LEFT(CONVERT(VARCHAR, CDate, 120), 10) + ''',' -- date
    + '''' + Str+ ''',' -- string
    + '''' + convert(nvarchar(50), Code)  + ''',' -- int
    + convert(nvarchar(50), Price) + ',' -- decimal
    + '''' + ISNULL(Tag, '''''') + '''' + ')'  -- nullable string

 from doc
 where CDate> '2019-01-01 00:00:00.000'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接