LoginSignup
4
2

More than 3 years have passed since last update.

SQLで小計行のある表を出力する

Last updated at Posted at 2020-05-31

やること

小計行のある表をSQLで出力する。

【小計行のある表の例】
小計行のある生鮮食品の売り上げ表。表の途中に小計値を出力する行がある。

商品 売上金額 数量
りんご 58440 725
みかん 9256 67
ぶどう 85024 242
小計(果物) 152720 1034
ブロッコリー 90361 330
小松菜 16754 359
小計(野菜) 107115 689

やり方

商品の売り上げを出力する行と合計値を出力する行をSQLでそれぞれ作成し、表示順に並び替える。

テーブル格納データ

以下の形でテーブルにデータが格納されているとする。

商品テーブル

ItemId ItemName
1 ぶどう
2 小松菜
3 ブロッコリー
4 りんご
5 みかん

売り上げテーブル

SalesDate ItemId Number Amount
2020/5/1 1 3 300
2020/5/3 1 2 200
2020/5/7 5 2 800
2020/5/8 2 1 150
2020/5/10 4 1 270
2020/5/12 3 6 1800
2020/5/15 2 4 600
2020/5/20 3 5 1500
2020/5/28 4 5 1350

作りたい表

作りたい表は以下である。

商品名 売上金額 数量
りんご 1620 6
みかん 800 2
ぶどう 500 5
小計(果物) 4550 21
ブロッコリー 3300 11
小松菜 750 5
小計(野菜) 2420 8

手順

1. 商品ごとに集計

GROUP BY句で商品ごとに集計する。

商品ごとに集計
SELECT
    Sales.ItemId      AS [商品Id]
   ,SUM(Sales.Amount) AS [売上金額]
   ,SUM(Sales.Number) AS [数量]
FROM
    Sales
GROUP BY
    Sales.ItemId
ORDER BY
    Sales.ItemId ASC

SQLの結果

商品Id 売上金額 数量
1 500 5
2 750 5
3 3300 11
4 1620 6
5 800 2

2. 小計行ごとに集計

今後は、小計行ごとに集計してみる。
テーブルには小計行のキーとなる商品カテゴリなどの列がないので、新たに一時テーブルを作り、商品カテゴリごとに商品を分類してから集計することにする。

小計を出す商品カテゴリごとに集計
-- 商品をカテゴリ分けするための一時テーブル
DECLARE @ItemCategory TABLE(
    Category Int NOT NULL,
    ItemId Int NOT NULL
)

-- 果物(1)と野菜(2)で商品をカテゴリ分けする。
INSERT INTO @ItemCategory VALUES (1,4),(1,5),(1,1),(2,2),(2,3)

SELECT
    ItemCategory.Category AS [小計]
   ,SUM(Sales.Amount)     AS [売上金額]
   ,SUM(Sales.Number)     AS [数量]
FROM
    Sales
    INNER JOIN @ItemCategory AS ItemCategory ON ItemCategory.ItemId = Sales.ItemId
GROUP BY
    ItemCategory.Category
ORDER BY
    ItemCategory.Category

SQLの結果

小計 売上金額 数量
1 2920 13
2 4050 16

3. 表に合わせて並び替える

表の出力順はテーブル上にデータとしてないので、こちらも一時テーブルで自作しよう。
先ほど書いた2つのSQLを書き直し、出力順が分かるようにする。

3-1. 表に行番号を振る

出力順を制御するにあたり、表に行番号を振る。

行番号 商品 売上金額 数量
1 りんご 58440 725
2 みかん 9256 67
3 ぶどう 85024 242
4 小計(果物) 152720 1034
5 ブロッコリー 90361 330
6 小松菜 16754 359
7 小計(野菜) 107115 689

3-2. 商品行に行番号を振る。

-- 商品ごとに行番号を振る
DECLARE @rowNumberItem TABLE(
    rowNumber Int NOT NULL,
    ItemCD Int NOT NULL
)
INSERT INTO @rowNumberItem VALUES (1,4),(2,5),(3,1),(5,3),(6,2)

SELECT
    rowNumber.rowNumber AS [行番号]
   ,Items.*
FROM
    (
    SELECT
        Sales.ItemId       AS [商品Id]
       ,SUM(Sales.Amount)  AS [売上金額]
       ,SUM(Sales.Number)  AS [数量]
    FROM
        Sales
    GROUP BY
        Sales.ItemId
    ) AS Items
    INNER JOIN @rowNumberItem AS rowNumber ON rowNumber.ItemCD = Items.[商品Id]
ORDER BY
    [行番号] ASC

SQLの結果

行番号 商品Id 売上金額 数量
1 4 1620 6
2 5 800 2
3 1 500 5
5 3 3300 11
6 2 750 5

3-3. 小計行に行番号を振る。

-- 行番号
DECLARE @rowNumberSubTotal TABLE(
    rowNumber Int NOT NULL,
    Category Int NOT NULL
)
INSERT INTO @rowNumberSubTotal VALUES (4,1),(7,2)

-- 商品をカテゴリ分けするための一時テーブル
DECLARE @ItemCategory TABLE(
    Category Int NOT NULL,
    ItemId Int NOT NULL
)

-- 果物(1)と野菜(2)で商品をカテゴリ分けする。
INSERT INTO @ItemCategory VALUES (1,4),(1,5),(1,1),(2,2),(2,3)

SELECT
    rowNumber.rowNumber AS [行番号],
    Subtotal.*
FROM
    (
    SELECT
        ItemCategory.Category AS [小計]
       ,SUM(Sales.Amount)     AS [売上金額]
       ,SUM(Sales.Number)     AS [数量]
    FROM
        Sales
        INNER JOIN @ItemCategory AS ItemCategory ON ItemCategory.ItemId = Sales.ItemId
    GROUP BY
        ItemCategory.Category
    ) AS Subtotal
    INNER JOIN @rowNumberSubTotal AS rowNumber ON rowNumber.Category = Subtotal.小計

SQLの結果

行番号 小計 売上金額 数量
4 1 2920 13
7 2 4050 16

3-4. 商品行と小計行を一緒に表示する

-- 商品ごとに行番号を振る
DECLARE @rowNumberItem TABLE(
    rowNumber Int NOT NULL,
    ItemCD Int NOT NULL
)
INSERT INTO @rowNumberItem VALUES (1,4),(2,5),(3,1),(5,3),(6,2)

-- 小計行ごとに行番号を振る
DECLARE @rowNumberSubTotal TABLE(
    rowNumber Int NOT NULL,
    Category Int NOT NULL
)
INSERT INTO @rowNumberSubTotal VALUES (4,1),(7,2)

-- 商品をカテゴリ分けするための一時テーブル
DECLARE @ItemCategory TABLE(
    Category Int NOT NULL,
    ItemId Int NOT NULL
)

-- 果物(1)と野菜(2)で商品をカテゴリ分けする。
INSERT INTO @ItemCategory VALUES (1,4),(1,5),(1,1),(2,2),(2,3)

-- 商品
SELECT
    rowNumber.rowNumber AS [行番号]
   ,Items.[売上金額]
   ,Items.[数量]
FROM
    (
    SELECT
        Sales.ItemId       AS [商品Id]
       ,SUM(Sales.Amount)  AS [売上金額]
       ,SUM(Sales.Number)  AS [数量]
    FROM
        Sales
    GROUP BY
        Sales.ItemId
    ) AS Items
    INNER JOIN @rowNumberItem AS rowNumber ON rowNumber.ItemCD = Items.[商品Id]
-- 小計
UNION ALL
SELECT
    rowNumber.rowNumber AS [行番号]
    ,Subtotal.[売上金額]
    ,Subtotal.[数量]
FROM
(
    SELECT
        ItemCategory.Category AS [小計]
       ,SUM(Sales.Amount)     AS [売上金額]
       ,SUM(Sales.Number)     AS [数量]
    FROM
        Sales
        INNER JOIN @ItemCategory AS ItemCategory ON ItemCategory.ItemId = Sales.ItemId
    GROUP BY
        ItemCategory.Category
    ) AS Subtotal
    INNER JOIN @rowNumberSubTotal AS rowNumber ON rowNumber.Category = Subtotal.小計
ORDER BY
    [行番号] ASC

SQLの結果

行番号 売上金額 数量
1 1620 6
2 800 2
3 500 5
4 2920 13
5 3300 11
6 750 5
7 4050 16

4. 商品名を出力する。

-- 商品ごとに行番号を振る
DECLARE @rowNumberItem TABLE(
    rowNumber Int NOT NULL,
    ItemCD Int NOT NULL
)
INSERT INTO @rowNumberItem VALUES (1,4),(2,5),(3,1),(5,3),(6,2)

-- 小計行ごとに行番号を振る
DECLARE @rowNumberSubTotal TABLE(
    rowNumber Int NOT NULL,
    Category Int NOT NULL
)
INSERT INTO @rowNumberSubTotal VALUES (4,1),(7,2)

-- カテゴリテーブル
DECLARE @Category TABLE(
    Category Int NOT NULL,
    CategoryName Varchar(50) NOT NULL
)
INSERT INTO @Category VALUES (1,'小計(果物)'),(2,'小計(野菜)')

-- 商品をカテゴリ分けするための一時テーブル
DECLARE @ItemCategory TABLE(
    Category Int NOT NULL,
    ItemId Int NOT NULL
)

-- 果物(1)と野菜(2)で商品をカテゴリ分けする。
INSERT INTO @ItemCategory VALUES (1,4),(1,5),(1,1),(2,2),(2,3)

-- 商品
SELECT
    rowNumber.rowNumber AS [行番号]
   ,Item.ItemName AS [商品名]
   ,Items.[売上金額]
   ,Items.[数量]
FROM
    (
    SELECT
        Sales.ItemId       AS [商品Id]
       ,SUM(Sales.Amount)  AS [売上金額]
       ,SUM(Sales.Number)  AS [数量]
    FROM
        Sales
    GROUP BY
        Sales.ItemId
    ) AS Items
    INNER JOIN @rowNumberItem AS rowNumber ON rowNumber.ItemCD = Items.[商品Id]
    INNER JOIN Item ON Item.ItemId = Items.[商品Id]
-- 小計
UNION ALL
SELECT
    rowNumber.rowNumber AS [行番号]
   ,Category.CategoryName AS [商品名]
   ,Subtotal.[売上金額]
   ,Subtotal.[数量]
FROM
(
    SELECT
        ItemCategory.Category AS [小計]
       ,SUM(Sales.Amount)     AS [売上金額]
       ,SUM(Sales.Number)     AS [数量]
    FROM
        Sales
        INNER JOIN @ItemCategory AS ItemCategory ON ItemCategory.ItemId = Sales.ItemId
    GROUP BY
        ItemCategory.Category
    ) AS Subtotal
    INNER JOIN @rowNumberSubTotal AS rowNumber ON rowNumber.Category = Subtotal.小計
    INNER JOIN @Category AS Category ON Category.Category = Subtotal.小計
ORDER BY
     [行番号] ASC

SQLの結果

行番号 商品名 売上金額 数量
1 りんご 1620 6
2 みかん 800 2
3 ぶどう 500 5
4 小計(果物) 2920 13
5 ブロッコリー 3300 11
6 小松菜 750 5
7 小計(野菜) 4050 16

目的とする表を出力できた。

4
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2