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 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

ただし、この方法ではテーブルが 2 回スキャンされます。

データを 2 回スキャンするのを避けるために、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

この方法では、テーブル スキャンは 1 つしかなく、サンプル データの最初の 2 つの行 (重複) が 1 つにマージされ、重複を別の行として保持する必要があることを除いて、必要なものはほとんど得られます。

質問: テーブル データが 1 回スキャンされ、重複が別の行として保持されるように、合計行が追加されたテーブル データを取得することは可能ですか?

望ましい結果は、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

行が重複していても、それらを一意にして問題を解決できます。これを行う 1 つの方法は、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

実行計画を比較すると、1 つのテーブル スキャンのみが実行されていることがわかります。

ここに画像の説明を入力

于 2015-07-21T08:52:00.093 に答える