ytooyamaのブログ

サーバ構築とか、仕事で発見したこととか、趣味のこととかを書いています。

DBでテーブル要素が全く同じテーブルの結合と集計

SQLはテーブル結合の方法がありすぎて、マジわかりませんよね。 例えばPostgreSQLの場合...

本を読んだりマニュアルを読んだりしましたが、わかったようなわからないような、そんなもやもやした感じで日々過ごしています。

売上合計してみる

毎回やるたびに忘れるので、よくやるやつをまとめておこうと思いました。 今回の場合、こんなテーブルがそれぞれあったとして、テーブルを縦につなげて、3つのテーブルを要するに30行のデータにして、amount_sold列のデータの合計を求めてみます。

testdb=# SELECT * FROM uriage2301;
 number | name  |  okashi   | amount_sold 
--------+-------+-----------+-------------
      1 | Alice | candy     |         100
      2 | Alice | candy     |          50
      3 | Alice | cookie    |         150
      4 | Bob   | chocolate |         200
      5 | Bob   | chocolate |         300
      6 | Jane  | cookie    |         150
      7 | Alice | chocolate |         180
      8 | Bob   | chocolate |         180
      9 | Bob   | chocolate |         180
     10 | Jane  | cookie    |         220
(10 行)

testdb=# SELECT * FROM uriage2302;
 number | name |  okashi   | amount_sold 
--------+------+-----------+-------------
      1 | Jane | chocolate |         120
      2 | Bob  | chocolate |         120
      3 | Ted  | cookie    |         120
      4 | Bob  | chocolate |         120
      5 | Bob  | chocolate |         120
      6 | Ted  | cookie    |         120
      7 | Jane | chocolate |         180
      8 | Jane | chocolate |         180
      9 | Bob  | cookie    |         120
     10 | Bob  | cookie    |         120
(10 行)

testdb=# SELECT * FROM uriage2303;
 number | name  |  okashi   | amount_sold 
--------+-------+-----------+-------------
      1 | Bob   | candy     |         120
      2 | Ted   | chocolate |         180
      3 | Jane  | candy     |         120
      4 | Alice | chocolate |         120
      5 | Bob   | chocolate |         120
      6 | Bob   | cookie    |         120
      7 | Jane  | chocolate |         280
      8 | Ted   | chocolate |         240
      9 | Bob   | cookie    |         180
     10 | Bob   | chocolate |         100
(10 行)

少なければそれぞれ合計を出して計算すれば良いですよね。

testdb=# SELECT sum(amount_sold) FROM uriage2301;
 sum  
------
 1710
(1 行)

testdb=# SELECT sum(amount_sold) FROM uriage2302;
 sum  
------
 1320
(1 行)

testdb=# SELECT sum(amount_sold) FROM uriage2303;
 sum  
------
 1580
(1 行)

これをあえて面倒くさい方法で求めてみます。

UNION ALLでテーブルをつなげる

テーブルは全く列のデータが同じ場合、UNION ALLを使って結合できます。 こんな感じです。

SELECT * FROM uriage2301
UNION ALL
SELECT * FROM uriage2302
UNION ALL
SELECT * FROM uriage2303
ORDER BY
1;

結果はこうなります。思ったとおりです。ORDER BY 1のお陰で良い感じに番号順に並んでくれています。 最初、UNIONを使っていて行数が合わなくて少し悩みました。

今回の例はデータ集計なので重複の除外はしてはいけません。というわけでUNION ALLを使うのが適切です。

 number | name  |  okashi   | amount_sold 
--------+-------+-----------+-------------
      1 | Alice | candy     |         100
      1 | Bob   | candy     |         120
      1 | Jane  | chocolate |         120
      2 | Bob   | chocolate |         120
      2 | Ted   | chocolate |         180
      2 | Alice | candy     |          50
      3 | Jane  | candy     |         120
      3 | Alice | cookie    |         150
      3 | Ted   | cookie    |         120
      4 | Alice | chocolate |         120
      4 | Bob   | chocolate |         200
      4 | Bob   | chocolate |         120
      5 | Bob   | chocolate |         300
      5 | Bob   | chocolate |         120
      5 | Bob   | chocolate |         120
      6 | Ted   | cookie    |         120
      6 | Jane  | cookie    |         150
      6 | Bob   | cookie    |         120
      7 | Alice | chocolate |         180
      7 | Jane  | chocolate |         280
      7 | Jane  | chocolate |         180
      8 | Jane  | chocolate |         180
      8 | Bob   | chocolate |         180
      8 | Ted   | chocolate |         240
      9 | Bob   | cookie    |         120
      9 | Bob   | chocolate |         180
      9 | Bob   | cookie    |         180
     10 | Jane  | cookie    |         220
     10 | Bob   | chocolate |         100
     10 | Bob   | cookie    |         120

それぞれのテーブルで小計してみる

それぞれのテーブルのamount_soldを計算する場合はこんな感じ。

SELECT sum(amount_sold)  FROM uriage2301
UNION ALL
SELECT sum(amount_sold)  FROM uriage2302
UNION ALL
SELECT sum(amount_sold)  FROM uriage2303
ORDER BY 1;
 sum  
------
 1320
 1580
 1710
(3 行) 

3つのテーブルのamount_soldを合計してみる

じゃあこれを合計するには? こんな感じです。サブクエリーを使っています。

SELECT sum(amount_sold) FROM
 (
 SELECT * FROM uriage2301
 UNION ALL
 SELECT * FROM uriage2302
 UNION ALL
 SELECT * FROM uriage2303
 ) AS t
 ORDER BY 1;
 sum  
------
 4610
(1 行)

やっていることは簡単なんですが、なかなか難しいです。 しかし、一つずつ覚えていくしかありません。

参考になった情報

この情報が参考になりました。

このブログサイトはJavaScriptを使っていますが、読み込んでいるJavaScriptは全てはてなが提供しているものであり、筆者が設置しているものではありません。