请考虑以下声明:
select stuff((
select '; ' + ([FIELD_1] + [FIELD_2] + [...] + [FIELD_N])
from [TABLE] t1
where t1.[ID] = t2.[ID]
for xml path ('')
),1,1, '')
from [TABLE] t2
如果该语句将具有相同ID
的10条记录串联在一起,但是所有记录都没有值(''或为空,而不是null
),则输出为:
; ; ; ; ; ; ; ; ; ;
如果填写了2条记录,我最终会得到
; ; ; AAA; ; ; ; BBB;
在这两种情况下,我分别希望分别是null
AAA; BBB
我试图像这样修复它:
select stuff((
select case when [FIELD_1] <> '' then '; ' + ([FIELD_1]) else '' end
from [TABLE] t1
where t1.[ID] = t2.[ID]
for xml path ('')
),1,1, '')
from [TABLE] t2
这有效,当我仅选择FIELD_1
时对我来说足够优雅。但是,当我选择许多隐藏字段(FIELD_1 + ... + FIELD_N
)时,这变得非常难看。
我在做什么错? stuff()
是否应该作为一个功能来解决我的问题?
答案 0 :(得分:3)
在WHERE
子句中添加条件以排除所有值为空字符串的行
select stuff((
select '; ' + ([FIELD_1] + [FIELD_2] + [...] + [FIELD_N])
from [TABLE] t1
where t1.[ID] = t2.[ID]
and [FIELD_1] + [FIELD_2] + [...] + [FIELD_N] <> ''
for xml path ('')
),1,1, '')
from [TABLE] t2
答案 1 :(得分:3)
此答案并非旨在显示一种更好的查询方法,而是旨在解释您所使用的查询。
要解决您的问题,您应该使用his answer中所示的where子句作为松鼠,而不要使用case
表达式。选择没有用的东西毫无意义。
我对这种字符串聚合方法感到非常困惑-太多的人在使用它而不了解其每个部分的作用-所以这里有一个简单的解释:
此技术包括三个部分:
汇总列中的值。 FOR XML PATH('')
就是这样做的。
FOR XML PATH('')
将返回一个xml字符串,其中xml标记是
查询的列名(或别名)。 (请参见cte_ForXml
和Aggregated
下面的示例脚本中的“列”)。
在值之间添加定界符。 ';' +
就是这样做的。
它还会从结果中删除列名XML标记-
通过将列名更改为空字符串。空别名在中无效
T-SQL,但是通过将另一个值连接到列,列名称可以
不再使用。
请参阅样本中的cte_ForXml_WithAnEmptyString
和OnlyValuesAggregated
脚本。
删除字符串开头的多余定界符。那就是
stuff
可以。
请参见示例脚本中的cte_FirstDlimiterRemoved
和FullQuery
。
stuff
的作用是在指定的index
处将一个字符串插入另一个字符串,同时从原始字符串中删除length
个字符。如果要插入空字符串,则只需从原始字符串中删除index
和length
参数指定的部分。
示例脚本,以说明此字符串聚合技术的不同步骤:
DECLARE @String_Agg AS TABLE
(
s varchar(10)
)
INSERT INTO @String_Agg (s) VALUES
('1'), ('2'), ('3')
;WITH cte_ForXml(Aggregated) AS
(
SELECT s
FROM @String_Agg
FOR XML PATH('')
)
, cte_ForXml_WithAnEmptyString(OnlyValuesAggregated) AS
(
SELECT '' + s
FROM @String_Agg
FOR XML PATH('')
)
, cte_ForXmlWithADelimiter(AggregatedWithADlimiter) AS
(
SELECT ';' + s
FROM @String_Agg
FOR XML PATH('')
), cte_FirstDlimiterRemoved(FullQuery) AS
(
SELECT STUFF
(
(
SELECT ';' + s
FROM @String_Agg
FOR XML PATH('')
), 1, 1, ''
)
)
SELECT Aggregated, OnlyValuesAggregated, AggregatedWithADlimiter, FullQuery
FROM cte_ForXml
CROSS JOIN cte_ForXml_WithAnEmptyString
CROSS JOIN cte_ForXmlWithADelimiter
CROSS JOIN cte_FirstDlimiterRemoved
结果:
Aggregated OnlyValuesAggregated AggregatedWithADlimiter FullQuery
<s>1</s><s>2</s><s>3</s> 123 ;1;2;3 1;2;3