SQL 服务器 - STRING_AGG 分隔符作为条件表达式
SQL Server - STRING_AGG separator as conditional expression
我需要根据任意逻辑使用不同的分隔符连接行。例如:
CREATE TABLE t(i INT, c VARCHAR(10));
INSERT INTO t(i,c) VALUES(1, 'a'),(2, 'b'),(3, 'c'),(4, 'd'),(5, 'e');
SELECT STRING_AGG(c,(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END))
WITHIN GROUP (ORDER BY i) AS r
FROM t;
它以错误结束:
Separator parameter for STRING_AGG must be a string literal or variable.
我的最终目标是获得:a OR b AND c OR d AND e
,例如:db<>fiddle demo
注意:我知道 XML + STUFF
或 @var = @var + ...
。
我正在搜索特定于 STRING_AGG
的 "workarounds"。
编辑:我已将其作为建议添加到 Azure Feedback
一个可能的解决方案(不理想)是将分隔符移动到主表达式并将分隔符设置为空白:
-- removing last separator
WITH cte AS (
SELECT STRING_AGG(c+(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END), '')
WITHIN GROUP (ORDER BY i)AS r
FROM t
)
SELECT r, REPLACE(REPLACE(r+'$', ' OR $', ''), ' AND $', '') AS r
,STUFF(r,
LEN(r)-CHARINDEX(' ', REVERSE(TRIM(r)))+1,
CHARINDEX(' ', REVERSE(TRIM(r)))+1,
'') AS r
FROM cte;
你快到了。只需颠倒顺序并使用东西,您就可以消除对 cte 和大多数字符串函数的需求:
SELECT STUFF(
STRING_AGG(
(IIF(i % 2 = 0, ' OR ', ' AND '))+c
, '') WITHIN GROUP (ORDER BY i)
, 1, 5, '') AS r
FROM t;
结果:a OR b AND c OR d AND e
由于第一行 i % 2
等于 1
,您知道 string_agg
结果总是以 and
开头:and a or b...
然后你所做的就是使用 stuff
从中删除前 5 个字符,然后你就可以回家了。
我还冒昧地将 CASE
表达式替换为更短的 IIF
更新
好吧,如果事先不知道 selected 分隔符,我无法想出一个单一的查询解决方案,但我仍然认为我找到了一个比你发布的更简单的解决方案- 使用 string_agg
将我对 cte 的初始解决方案和使用 stuff
的 select 分开,同时通过重复条件确定分隔符的长度:
WITH CTE AS
(
SELECT MIN(i) As firstI,
STRING_AGG(
(IIF(i % 2 = 0, ' OR ', ' AND '))+c
, '') WITHIN GROUP (ORDER BY i)
AS r
FROM t
)
SELECT STUFF(r, 1, IIF(firstI % 2 = 0, 4, 5), '') AS r
FROM CTE;
我需要根据任意逻辑使用不同的分隔符连接行。例如:
CREATE TABLE t(i INT, c VARCHAR(10));
INSERT INTO t(i,c) VALUES(1, 'a'),(2, 'b'),(3, 'c'),(4, 'd'),(5, 'e');
SELECT STRING_AGG(c,(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END))
WITHIN GROUP (ORDER BY i) AS r
FROM t;
它以错误结束:
Separator parameter for STRING_AGG must be a string literal or variable.
我的最终目标是获得:a OR b AND c OR d AND e
,例如:db<>fiddle demo
注意:我知道 XML + STUFF
或 @var = @var + ...
。
我正在搜索特定于 STRING_AGG
的 "workarounds"。
编辑:我已将其作为建议添加到 Azure Feedback
一个可能的解决方案(不理想)是将分隔符移动到主表达式并将分隔符设置为空白:
-- removing last separator
WITH cte AS (
SELECT STRING_AGG(c+(CASE WHEN i%2=0 THEN ' OR ' ELSE ' AND ' END), '')
WITHIN GROUP (ORDER BY i)AS r
FROM t
)
SELECT r, REPLACE(REPLACE(r+'$', ' OR $', ''), ' AND $', '') AS r
,STUFF(r,
LEN(r)-CHARINDEX(' ', REVERSE(TRIM(r)))+1,
CHARINDEX(' ', REVERSE(TRIM(r)))+1,
'') AS r
FROM cte;
你快到了。只需颠倒顺序并使用东西,您就可以消除对 cte 和大多数字符串函数的需求:
SELECT STUFF(
STRING_AGG(
(IIF(i % 2 = 0, ' OR ', ' AND '))+c
, '') WITHIN GROUP (ORDER BY i)
, 1, 5, '') AS r
FROM t;
结果:a OR b AND c OR d AND e
由于第一行 i % 2
等于 1
,您知道 string_agg
结果总是以 and
开头:and a or b...
然后你所做的就是使用 stuff
从中删除前 5 个字符,然后你就可以回家了。
我还冒昧地将 CASE
表达式替换为更短的 IIF
更新
好吧,如果事先不知道 selected 分隔符,我无法想出一个单一的查询解决方案,但我仍然认为我找到了一个比你发布的更简单的解决方案- 使用 string_agg
将我对 cte 的初始解决方案和使用 stuff
的 select 分开,同时通过重复条件确定分隔符的长度:
WITH CTE AS
(
SELECT MIN(i) As firstI,
STRING_AGG(
(IIF(i % 2 = 0, ' OR ', ' AND '))+c
, '') WITHIN GROUP (ORDER BY i)
AS r
FROM t
)
SELECT STUFF(r, 1, IIF(firstI % 2 = 0, 4, 5), '') AS r
FROM CTE;