TL;DR:我们可以在使用 GROUP BY ROLLUP(...) 的查询中使用 STRING_AGG 聚合函数吗?
我正在转换使用 STUFF( (SELECT...FOR XML) ) 方法的旧代码,以便它使用 STRING_AGG 代替。
使用 ROLLUP 时我似乎无法使用 STRING_AGG,因为我收到错误
与 CUBE、ROLLUP 或 GROUPING SET 查询一起使用的聚合函数必须提供子聚合的合并。要解决此问题,请删除聚合函数或在 GROUP BY 子句上使用 UNION ALL 编写查询。
有效的代码,只需使用 GROUP BY ....
DROP TABLE IF EXISTS RollupTest
CREATE TABLE RollupTest (UserId INT, RoleName VARCHAR(20));
INSERT RollupTest VALUES (1, 'Boss'), (1, 'Dogsbody'), (2, 'Dogsbody'), (2, 'another'), (2, 'parent'), (3, 'another')
SELECT UserId, NumRoles=COUNT(*), RoleNames=STRING_AGG(RoleName, ', ')
FROM RollupTest
GROUP BY UserId
/* output is...
UserId NumRoles RoleNames
----------- ----------- -------------------------
1 2 Boss, Dogsbody
2 3 Dogsbody, another, parent
3 1 another
*/
更改为使用 ROLLUP 获取总计行,期望为总计行中的聚合名称列获取 NULL...
DROP TABLE IF EXISTS RollupTest
CREATE TABLE RollupTest (UserId INT, RoleName VARCHAR(20));
INSERT RollupTest VALUES (1, 'Boss'), (1, 'Dogsbody'), (2, 'Dogsbody'), (2, 'another'), (2, 'parent'), (3, 'another')
SELECT UserId, NumRoles=COUNT(*), RoleNames=STRING_AGG(RoleName, ', ')
FROM RollupTest
GROUP BY ROLLUP(UserId) --<<< just added ROLLUP here
/* expected output to be something like the following...
UserId NumRoles RoleNames
----------- ----------- -------------------------
1 2 Boss, Dogsbody
2 3 Dogsbody, another, parent
3 1 another
NULL 6 NULL
*/
...我们得到了错误。 我尝试使用 GROUPING(...) 来尝试避免在总计行上调用 STRING_AGG() ,但这没有什么区别。
我想这很明显,也许 STRING_AGG() 出于合理的原因无法被汇总,但我看不到它。我不认为错误消息有帮助,但我可能有点密集。 当然,使用 FOR XML 的旧方法可以与 ROLLUP 一起使用。
正如您所见,在
STRING_AGG
中使用任何类型的分组集时,不允许使用 GROUP BY
。
您可以按如下方式破解它
SELECT
UserId,
NumRoles = SUM(NumUsers),
RoleNames = STRING_AGG(RoleName, ', ')
FROM (
SELECT
UserId,
RoleName,
NumUsers = COUNT(*),
IsGrouped = GROUPING(UserId)
FROM RollupTest rt
GROUP BY GROUPING SETS (
(UserId, RoleName),
(RoleName)
)
) rt
GROUP BY
IsGrouped,
UserId
ORDER BY
IsGrouped,
UserId;
这里的想法如下:
GROUPING SETS
将汇总行分解为单独的 UserId, NULL
行。计算该级别的总计数。您仍然可以获得所有原始行。UserId
和 IsGrouped
IsGrouped
列进行排序和条件判断,但这并不是绝对必要的。请注意,此解决方案中没有使用自连接或窗口函数,尽管它确实需要第二次排序。
将数据插入临时和分组依据
SELECT value AS UserId
INTO #a
FROM STRING_SPLIT(@ObjectIds, ',')
GROUP BY value;
然后进行聚合
SELECT @ObjectIds = STRING_AGG(UserId, ',')
FROM #a
祝你好运