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;

db<>fiddle demo

它以错误结束:

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;

db<>fiddle demo

你快到了。只需颠倒顺序并使用东西,您就可以消除对 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

db<>fiddle demo

由于第一行 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;

db<>fiddle demo #2