想象一下,我们在表格中有以下数据:
groupName volume class mark
---------- ------- ------ ----
group1 50 1 o
group1 50 1 o
group1 50 1 x
group1 25 2 o
group2 25 1 x
group2 17 3 x
group2 11 2 o
group3 11 1 o
group3 19 3 x
最后需要添加总计行(SUM
表示卷,NULL
表示其他列。
我知道我需要的是通过将union all
添加为:
select 0 as isTotal, groupName, class, mark, volume
from dataTable
union all
select 1, NULL, NULL, NULL, sum(volume)
from dataTable
order by isTotal, groupName, class
但这种表格会被扫描两次。
为避免两次扫描数据,我尝试使用group by
:
select grouping(groupName) as isTotal, groupName, class, mark, sum(volume) as volume
from dataTable
group by grouping sets ((), (groupName, class, mark, volume))
order by isTotal, groupName, class
这种方式只有一个表扫描,我几乎得到了我需要的东西,除了样本数据的两个第一行(它们是重复的)合并为一个,我需要将重复项保存为单独的行
问题: 是否可以获取添加了总计行的表数据,以便扫描表数据一次,并将重复数据保存为单独的行?
期望的结果是union all
查询返回的内容:
isTotal groupName class mark volume
------- ----------- ------ ---- -------
0 group 1 1 o 50
0 group 1 1 o 50
0 group 1 1 x 50
0 group 1 2 o 25
0 group 2 1 x 25
0 group 2 2 o 11
0 group 2 3 x 17
0 group 3 1 o 11
0 group 3 3 x 19
1 NULL NULL NULL 258
group by grouping sets
查询返回的结果:
isTotal groupName class mark volume
------- ---------- ------ ---- -------
0 group 1 1 o 100
0 group 1 1 x 50
0 group 1 2 o 25
0 group 2 1 x 25
0 group 2 2 o 11
0 group 2 3 x 17
0 group 3 1 o 11
0 group 3 3 x 19
1 NULL NULL NULL 258
答案 0 :(得分:2)
即使您认为自己有重复的行,也可以让它们与众不同并解决您的问题。一种方法是使用ROW_NUMBER
函数。
例如:
DECLARE @DataSource TABLE
(
[groupName] VARCHAR(6)
,[volume] TINYINT
,[class] TINYINT
,[mark] CHAR(1)
);
INSERT INTO @DataSource ([groupName], [volume], [class], [mark])
VALUES ('group1', '50', '1', 'x')
,('group1', '50', '1', 'x')
,('group1', '50', '1', 'o')
,('group1', '25', '2', 'o')
,('group2', '25', '1', 'x')
,('group2', '17', '3', 'x')
,('group2', '11', '2', 'o')
,('group3', '11', '1', 'o')
,('group3', '19', '3', 'x');
WITH DataSource ([rowID], [groupName], [volume], [class], [mark]) AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
,[groupName]
,[volume]
,[class]
,[mark]
FROM @DataSource
)
SELECT GROUPING([groupName]) as [isTotal]
,[groupName]
,[class]
,[mark]
,SUM([volume]) AS [volume]
FROM DataSource
GROUP BY GROUPING SETS ((), ([rowID], [groupName], [volume], [class], [mark]))
ORDER BY [isTotal]
,[groupName]
,[class];
会给你:
与初始查询完全相同:
select 0 as isTotal, groupName, class, mark, volume
from @DataSource
union all
select 1, NULL, NULL, NULL, sum(volume)
from @DataSource
order by isTotal, groupName, class
如果比较执行计划,则只能看到一个表扫描: