【SQL】集約キー:GROUP BY句に書くもの

  • #SQL

集約キーとは

  • GROUP BY句に書いた列名のこと
  • 集約キーは複数指定できる

集約キーがひとつ

/* 集約キー:shohin_bunrui */
SELECT shohin_bunrui, COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui;

 shohin_bunrui | count 
---------------+-------
 キッチン用品  |     4
 衣服          |     2
 事務用品      |     2
/* 集約キー:torokubi */
SELECT torokubi, COUNT(*)
FROM Shohin
GROUP BY torokubi;
  torokubi  | count 
------------+-------
            |     1
 2009-11-11 |     1
 2009-09-20 |     3
 2009-09-11 |     1
 2009-01-15 |     1
 2008-04-28 |     1

集約キーがふたつ

/* 集約キー:shohin_bunrui, torokubi */
SELECT shohin_bunrui, torokubi, COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui, torokubi;

 shohin_bunrui |  torokubi  | count 
---------------+------------+-------
 衣服          |            |     1
 キッチン用品  | 2009-01-15 |     1
 衣服          | 2009-09-20 |     1
 キッチン用品  | 2008-04-28 |     1
 事務用品      | 2009-11-11 |     1
 事務用品      | 2009-09-11 |     1
 キッチン用品  | 2009-09-20 |     2

集約キーがみっつ

/* 集約キー:shohin_mei, shohin_bunrui, torokubi */
SELECT shohin_mei, shohin_bunrui, torokubi, COUNT(*)
FROM Shohin
GROUP BY shohin_mei, shohin_bunrui, torokubi;

   shohin_mei   | shohin_bunrui |  torokubi  | count 
----------------+---------------+------------+-------
 フォーク       | キッチン用品  | 2009-09-20 |     1
 包丁           | キッチン用品  | 2009-09-20 |     1
 圧力鍋         | キッチン用品  | 2009-01-15 |     1
 穴あけパンチ   | 事務用品      | 2009-09-11 |     1
 カッターシャツ | 衣服          |            |     1
 ボールペン     | 事務用品      | 2009-11-11 |     1
 おろしがね     | キッチン用品  | 2008-04-28 |     1
 Tシャツ        | 衣服          | 2009-09-20 |     1
  1. 集約キーが増える
  2. グループが細分化されてくる
  3. 重複しない列が集約キーに含まれると、集約(グループ化)の意味はなくなる
  4. すべての列を集約キーにすると、集約(グループ化)の意味はなくなる

SELECT句に集約キーを書かなくても動く

ただ、書かないと何で集約したか表示されないので読みにくすぎる

/* SELECT句に集約キーを書かない */

SELECT COUNT(*)
FROM Shohin
GROUP BY shohin_mei, shohin_bunrui, torokubi;

 count 
-------
     1
     1
     1
     1
     1
     1
     1
     1

-- ****************

SELECT COUNT(*)
FROM Shohin
GROUP BY torokubi;

 count 
-------
     1
     1
     3
     1
     1
     1

-- ****************

SELECT COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui;

 count 
-------
     4
     2
     2

【注意】ASで付けた別名は集約キーにならない

  • 別名はあくまで「表示用の呼び名」
  • 集約キーになるのは元の列
  • 別名が元の列名と被ると、元の列として解釈される
    (意図と違うグループ化がされてしまううえに、気づきにくい事故が起きる)

前提:PostgreSQLの場合

  1. GROUP BYに書かれた名前は、まず本物の列名として探す
  2. なければ別名として扱う

【検証①】別名に実在する列名をつける

/* ①shiire_tanka, hanbai_tanka が実在するか確認 */
SELECT shiire_tanka, hanbai_tanka            
FROM Shohin;

/* 実在する列名だった */
 shiire_tanka | hanbai_tanka 
--------------+--------------
          500 |         1000
          320 |          500
         2800 |         4000
         2800 |         3000
         5000 |         6800
              |          500
          790 |          880
              |          100
/* ②「shiire_tanka」に「hanbai_tanka」と別名をつける
		集約キーは「hanbai_tanka」(shiire_tankaの別名)とする */
		
SELECT shiire_tanka AS hanbai_tanka, COUNT(*)
FROM Shohin
GROUP BY hanbai_tanka;
/* 実行するとエラーが発生 */
ERROR:  column "shohin.shiire_tanka" must appear in the GROUP BY clause or be used in an aggregate function

/* エラー内容
列 "shohin.shiire_tanka" は、`GROUP BY`句に書かれているか、
集約関数の中で使われているかの、どちらかでなければなりません 

前提①に基づき、本物の列として扱ったためエラーとなった */

【検証②】別名が実在する列名とかぶらない

注意:PostgreSQLでは通るが、他のDBMSではエラーになる可能性がある

SELECT shiire_tanka AS "仕入単価", COUNT(*)
FROM Shohin 
GROUP BY 仕入単価;

/* 前提②に基づき、「仕入単価」を別名として扱った */
 仕入単価 | count 
----------+-------
          |     2
      320 |     1
      500 |     1
     2800 |     2
     5000 |     1
      790 |     1

【結論】集約キーに別名を使わない

  • 別名の文字列を変えただけで、エラーが出たり出なかったりする
  • DBMSによって結果が異なる
  • 結果の正確さが担保できない

関連記事:【SQL】GROUP BY:グループに切り分ける

参考書籍:ミック『SQL 第2版 ゼロからはじめるデータベース操作』(翔泳社)