2

假设我们在表中有以下数据:

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 allas 相加来实现:

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
4

1 回答 1

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

如果您比较执行计划,您会发现只执行了一次表扫描:

在此处输入图像描述

于 2015-07-21T08:52:00.093 回答