web-dev-qa-db-ja.com

SUM(列)の合計を計算します

特定のアイテムの数量(itemid)と製品の日付コード(proddte)を合計するこのコードがあります。

select sum(qty), itemid, proddte 
from testtable where .... 
group by itemid, proddte

私がやりたいのは、itemid/proddteに関係なく、すべてのqtyの合計を取得することです。私が試してみました:

select sum(qty), itemid, proddte, sum(qty) over() as grandtotal 
from testtable 
where .... 
group by itemid, proddte

ただし、group by句にはqtyも含める必要があると記載されています。そうした場合、結果は期待した結果とは異なります。

すべての行が同じ値で、個別の列として表される必要はありません。全体の合計を表示できる限り、どのような表現でも受け入れられます。

9
niq
_CREATE TABLE #foo
(
 itemid int, 
 proddte date,
 qty int
);

INSERT #foo(itemid,proddte,qty) VALUES
(1,'20140101',5),(1,'20140102',7),(2,'20150101',10);


-- if it really needs to be a column with the same value
-- in every row, just calculate once and assign it to a variable

DECLARE @sum int = (SELECT SUM(qty) FROM #foo);

SELECT itemid, proddte, GroupedSum = SUM(qty), GrandTotal = @sum
  FROM #foo
  GROUP BY itemid, proddte;

-- if the grand total can be expressed on its own row, 
-- you can use GROUP BY GROUPING SETS:
SELECT itemid, proddte, SUM(qty)
  FROM #foo GROUP BY GROUPING SETS((),(itemid,proddte));

-- if that syntax is confusing, you can use a less
-- efficient UNION ALL:
SELECT itemid, proddte, SUM(qty)
  FROM #foo GROUP BY itemid,proddte
UNION ALL
SELECT NULL, NULL, SUM(qty) 
  FROM #foo;

GO
DROP TABLE #foo;
_

_GROUP BY GROUPING SETS_は基本的に_UNION ALL_です。 _()_は、グループ化に関係なくSUMを取るだけで、リストされている他のグループは個別に集計されます。 GROUP BY GROUPING SETS ((itemid),(itemid,proddte))を試して、違いを確認してください。

詳細については、ドキュメントを参照してください:

GROUP BYとROLLUP、CUBE、およびGROUPING SETSを併用

Andriyが述べたように、上記のクエリは次のように記述することもできます。

_GROUP BY ROLLUP( (itemid,proddte) )
_

そこにある2つの列は、追加の括弧のペアで囲まれているため、1つの単位になっています。 Andriy デモを書きました Stack Exchange Data Explorerでホストされています。

9
Aaron Bertrand

これも有効な構文です:

_       sum(sum(qty)) over ()
_

最初はそれを見ると少し混乱しますが、ウィンドウが機能していることだけ覚えておく必要があります。 sum() over ()-_group by_の後に適用されるため、クエリによるグループの選択リストに表示される可能性のあるすべてのものをウィンドウ集約の内部に配置できます。したがって、(qtyはできますが)sum(qty)sum() over ()内に配置できます。

_select sum(qty), itemid, proddte, 
       sum(sum(qty)) over () as grandtotal  
from testtable 
where .... 
group by itemid, proddte ;
_

そうは言っても、Aaron Bertrandが提供する_GROUPING SETS_クエリを使用することをお勧めします。合計をすべての行に表示するのではなく、一度表示する必要があります。

また、合計の合計は合計の計算に使用できますが、合計数が必要な場合は、カウントの合計ではなく合計数を使用する必要があります。

_sum(count(*)) over ()  as grand_count
_

また、テーブル全体の平均が必要な場合は、さらに複雑になります。

_sum(sum(qty)) over ()
/ sum(count(qty)) over ()  as grand_average
_

平均の平均がすべての平均と同じではないためです。 (avg(avg(qty)) over ()を試してみると、上記の総平均とは異なる結果が得られる場合があります。)

10
ypercubeᵀᴹ

回避策の1つは、最初のGROUP BY[〜#〜] cte [〜#〜] にラップすることです。

WITH
CTE
AS
(
    select
        itemid
        ,proddte
        ,sum(qty) AS SumQty
    from testtable 
    where .... 
    group by itemid, proddte
)
SELECT
    itemid
    ,proddte
    ,SumQty
    ,SUM(SumQty) OVER () AS grandtotal
FROM CTE
;
3