STRING_AGG 可以多次使用不同的分隔符吗?

Ste*_*ble 9 sql-server sql-server-2017

我正在做一些字符串聚合,并注意到对我来说看起来像一个错误。STRING_AGG在具有不同分隔符参数的同一查询中使用了两次。但是,两者都产生了相同的结果(在两种情况下都使用“第一个”分隔符)。它似乎只在某些情况下发生。这是错误还是记录在案的行为?

首先,设置:

CREATE TABLE #Data
  ([Group] INT
 , Member  CHAR(1));

INSERT INTO #Data
VALUES (1, 'a'), (1, 'b')
     , (2, 'c'), (2, 'd');
Run Code Online (Sandbox Code Playgroud)

从表与VALUES构造函数。没有WITHIN GROUP ORDER BY,一切都很好。有了它,bug就出现了

SELECT Commas = STRING_AGG(Member, ', ') --WITHIN GROUP(ORDER BY Member)
     , Colons = STRING_AGG(Member, '::') --WITHIN GROUP(ORDER BY Member)
FROM #Data;

SELECT Commas = STRING_AGG(Member, ', ') --WITHIN GROUP(ORDER BY Member)
     , Colons = STRING_AGG(Member, '::') --WITHIN GROUP(ORDER BY Member)
FROM (VALUES (1, 'a'), (1, 'b')
           , (2, 'c'), (2, 'd')) [v] ([Group], Member);
Run Code Online (Sandbox Code Playgroud)

添加 aGROUP BY添加了一个排序,现在两种情况都存在错误:

SELECT [Group]
     , Commas = STRING_AGG(Member, ', ')
     , Colons = STRING_AGG(Member, '::')
FROM #Data
GROUP BY [Group];

SELECT [Group]
     , Commas = STRING_AGG(Member, ', ')
     , Colons = STRING_AGG(Member, '::')
FROM (VALUES (1, 'a'), (1, 'b')
           , (2, 'c'), (2, 'd')) [v] ([Group], Member)
GROUP BY [Group];
Run Code Online (Sandbox Code Playgroud)

添加它肯定坏了......就像在内心深处一样。将两个表达式组合在 a 中HAVING,您将一无所获。单独使用其中一个,您就可以获得数据。

SELECT [Group]
     , Colons = STRING_AGG(Member, '::')
     , Commas = STRING_AGG(Member, ', ')
FROM #Data
GROUP BY [Group]
HAVING STRING_AGG(Member, ', ') LIKE '%, %'
   AND STRING_AGG(Member, '::') LIKE '%::%';
Run Code Online (Sandbox Code Playgroud)

切换列的顺序会切换使用的分隔符。

我使用这些跟踪标志进行调查,但找不到关于“优化”第二个聚合的任何信息。

OPTION (QUERYTRACEON 3604 -- Output info to client
      , QUERYTRACEON 8619 -- Show applied optimization rules
      , QUERYTRACEON 8606 -- Show logical query trees
      , QUERYTRACEON 8607 -- Show physical query tree
      , RECOMPILE);
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 8

这是一个错误。此答案表明它已在 CU17 中修复,但我刚刚对其进行了测试并发现它是否定的(并且没有迹象表明该修复程序打算在此处向后移植)。

我试过

SELECT [Group]
     , Commas = STRING_AGG(Member, ', ')
     , Colons = STRING_AGG(Member, '::')
FROM (VALUES (1, 'a'), (1, 'b')
           , (2, 'c'), (2, 'd')) [v] ([Group], Member)
GROUP BY [Group]
OPTION (QUERYTRACEON 3604 -- Output info to client
      , QUERYTRACEON 8607 -- Optimization output tree, before post-optimization rewrite phase.
      , QUERYTRACEON 7352 -- The final query tree after Post-optimization re-write.
      , RECOMPILE);
;
Run Code Online (Sandbox Code Playgroud)

在 2017 年 CU17。这给出了计划

在此处输入图片说明

2019 年没有计算标量,流聚合已定义值

[Expr1010] = Scalar Operator(STRING_AGG([Union1009],', ')), 
[Expr1011] = Scalar Operator(STRING_AGG([Union1009],'::'))
Run Code Online (Sandbox Code Playgroud)

2017 年,Stream Aggregate 定义了值

[Expr1010] = Scalar Operator(STRING_AGG([Union1009],', '))
Run Code Online (Sandbox Code Playgroud)

还有一个额外的 Compute Scalar with expression

[Expr1011] = Scalar Operator([Expr1010])
Run Code Online (Sandbox Code Playgroud)

跟踪标志的输出8607在 2017 年和 2019 年相同,但7352有所不同,所以我认为这是一个错误的优化后重写。

作为一种解决方法,您可以更改表达式以执行如下无操作以防止这种错误的优化。

SELECT [Group]
     , Commas = STRING_AGG(Member, ', ')
     , Colons = STRING_AGG('' + Member, '::')
Run Code Online (Sandbox Code Playgroud)