【SQL超入門講座】07.HAVING|グループ化したデータの中からデータ抽出

こんにちは。キノコードです。
前回のレッスンでは、グルーピングをするGROUP BYについて説明しました。
つまり、そのレッスンで、SELECT文にGROUP BYを付けることでデータをグルーピングできるとお伝えしました。
今回のこのレッスンで紹介するのは、HAVINGです。
HAVINGは、グルーピングされたデータの中から、さらも特定の条件でデータ抽出したいときに使います。
ここまで聞いて、あれ?と思われた方がいらっしゃるかもしれません。
レッスン04で解説したWHEREも、特定の条件で抽出するものです。
HAVINGとWHEREの違いは、WHEREが単純にテーブル内のデータを抽出するのに対し、HAVINGはグルーピングしたデータからさらに抽出条件を付けられるという点が異なります。
これだけだとわかりにくいと思うので、レッスンの中で比較しながら解説をしていきます。
キノコードでは、人気言語のPython超入門講座、Pythonを使ったデータ集計データ加工のPandas入門講座、仕事の自動化の講座、人工知能のレッスンもアップしています。
チャンネル登録していただけますと新着通知がいきますので、ぜひチャンネル登録をお願いします。
それでは、レッスンスタートです。

HAVINGとは

HAVINGは、グルーピングされたデータの中から、さらに特定の条件でデータ抽出したいときに使います。
「グルーピングされたデータの中から」というのがポイントです。
覚えておいてくださいね。
それでは、使い方を見ていきましょう。

HAVINGの使い方

SELECT グルーピングをするカラム、集計関数(集計対象カラム)  
FROM テーブル名
WHERE 条件式
GROUP BY グルーピングをするカラム
HAVING 集計関数(集計対象カラム)で条件式
ORDER BY ソート条件


HAVINGの構文はこちらです。
HAVINGはGROUP BYとORDER BYの間に記述します。
また、HAVINGには、集計関数(集計対象カラム)で、条件式を記述する必要があります。
ちょっと難しくなってきたので、HAVINGの具体例を見る前に、GROUP BYのおさらいをしましょう。
次のSQLを実行します。

SELECT
    商品名
    , sum(売上金額)
FROM test_table
GROUP BY 商品名


商品名を起点に売上金額の合計を算出します。
実行します。
ここまでが前回のお話です。
今回はもう一歩進んで「売上金額が100万円以上の商品名のみ抽出」してみましょう。
どうSQLで記述するかみていきましょう。

SELECT
    商品名
    , sum(売上金額)
FROM test_table
GROUP BY 商品名
HAVING sum(売上金額) >= 1000000

このSQLを実行すると、売上金額が100万円以上の商品名のみ抽出することができます。
HAVINGに集約関数を含んだカラムを直接条件式に入れ込むことで、HAVINGを元にしたデータ抽出できます。
100万円以上の商品名のみ抽出することができました。

HAVINGとWHEREの違い


ここまで解説を聞いて、「結局WHEREとHAVINGって何が違うんだ?」と感じた方もいらっしゃると思います。
WHEREとHAVINGの整理をします。
WHEREもHAVINGもやっていることは同じで、どちらもデータに対して抽出処理を実行します。
異なるのは呼ばれるタイミングのみです。
実はデータベースがSQLの各コマンドを解釈するのは、単純に上から下へ1行ずつ見ていくのではなく、ちゃんと順番があります。
SQLの呼ばれる順番は次の通りです。

s_04

この図から分かる通り、SQLはSELECTではなくFROMから呼ばれ、WHERE、GROUP BY、HAVING、その後にSELECTが呼ばれる、という流れになっています。
なので、WHEREはGROUP BYよりも前に、HAVINGはGROUP BYのあとに呼ばれています。
これは言い換えると「WHEREはGROUP BYされる前のデータに抽出条件を付与する」
そして、「HAVINGはGROUP BYされた後のデータに抽出条件を付与する」という流れです、
SQLが呼ばれる順を復習すると、「どのテーブルの、どのデータを、どうグルーピングし、グルーピングしたデータをどう抽出し、どのカラムを表示するか」という流れになります。
試しにWHEREに集約関数を含んだカラムを指定したらどうなるか見てみましょう。
次のSQLを実行します。

SELECT
    商品名
    , sum(売上金額)
FROM
    test_table
WHERE
    sum(売上金額) >= 1000000
GROUP BY
    商品名


このSQLを実行すると次のエラーが表示されます。
直訳で「集約の誤用」と表示されています。
このように、WHERE句が呼ばれる時点ではGROUP BYはまだ呼ばれていないので、WHRER内で集約関数を使うことができません。

WHEREとHAVINGを同時に使う

SELECT
    商品名
    , sum(売上金額)
FROM
    test_table
WHERE
    商品名 !='ジャケット'
GROUP BY
    商品名
HAVING
    sum(売上金額) <= 1000000

最後にWHEREとHAVINGを同時に使うとどういったことができるのかを見ていきましょう。
WHEREとHAVINGは似ていますが役割が異なります。
両方をうまく使うことでより複雑な抽出や集計が可能になります。
ここでは「ジャケット以外の売上金額の合計を集計し、売上金額が100万円以下のみのデータ」出力してみましょう。

先ほど説明した通り、SQLの呼ばれる順番通り、GROUP BYの前にWHEREが呼ばれます。
WHEREの!=は否定なので、ジャケット以外のデータを抽出しています。
次にGROUP BYで商品名でグルーピングして合計を算出します。
最後にHAVINGが呼びだされ、売上金額が100万円以下のみのデータを抽出しています。
実行します。
抽出できました。
このようにWHEREとHAVINGを使い分けることで、難しい要件にもSQL1つで対応できるようになります。