[SQL] HAVING句とWHERE句の違い

今回はSQLの HAVING 句について解説する。 HAVING 句は WHERE 句と同様にデータのフィルタリングを行うが、その適用タイミングと対象が異なる。

SQL初学者が最もつまずきやすいポイントの一つである「WHEREHAVING の使い分け」について、実例を交えて見ていく。

準備

本サイトではpythonのライブラリであるsqlite3とipython-sqlを利用して、Jupyter Notebook上でSQLを実行・解説する。 また、データフレームの表示には Polars を利用する。

github

  • githubのjupyter notebook形式のファイルはこちら

google colaboratory

  • google colaboratory で実行する場合はこちら

筆者の環境

筆者の環境である。

!sw_vers
ProductName:		macOS
ProductVersion:		15.5
BuildVersion:		24F74
!python -V
Python 3.12.12

必要なライブラリを読み込む。

import sqlite3
import polars as pl

%load_ext sql
%config SqlMagic.feedback = True

%config SqlMagic.style = '_DEPRECATED_DEFAULT'

データの準備

サンプルとして、顧客ごとの注文データを格納した Orders テーブルを作成する。

import os

if os.path.exists("data.db"):
    os.remove("data.db")

os.system("touch data.db")
os.system("chmod 664 data.db")

# データベース接続
%sql sqlite:///data.db
'Connected: @data.db'
%%sql
CREATE TABLE Orders (
    id INTEGER PRIMARY KEY,
    customer_id INTEGER,
    amount INTEGER
);

INSERT INTO Orders (customer_id, amount) VALUES
    (1, 100),
    (1, 200),
    (2, 500),
    (3, 100),
    (3, 100),
    (3, 100),
    (4, 1000);
 * sqlite:///data.db
Done.
7 rows affected.





[]
%%sql
SELECT * FROM Orders;
 * sqlite:///data.db
Done.
idcustomer_idamount
11100
21200
32500
43100
53100
63100
741000

課題:注文合計金額が400以上の顧客を抽出する

顧客ごと(customer_id)に amount を合計し、その結果が400以上の顧客だけを表示したい。

間違い:WHERE句で集計結果をフィルタリングしようとする

以下のようなクエリはエラーになる。

SELECT
    customer_id,
    SUM(amount) as total_amount
FROM
    Orders
WHERE
    SUM(amount) >= 400
GROUP BY
    customer_id;

理由: WHERE 句は 集計前 の行に対してフィルタリングを行うため、集計関数(SUM など)を条件に指定できないからである。

正解:HAVING句を使用する

集計後の結果に対してフィルタリングを行う場合は、HAVING 句を使用する。

query = """
SELECT
    customer_id,
    SUM(amount) as total_amount
FROM
    Orders
GROUP BY
    customer_id
HAVING
    SUM(amount) >= 400;
"""

with sqlite3.connect("data.db") as conn:
    df = pl.read_database(query, connection=conn)
    display(df)

shape: (2, 2)

customer_idtotal_amount
2500
41000

解説:実行順序

SQLの実行順序を理解すると、違いが明確になる。

  1. FROM: 対象テーブルを選択
  2. WHERE: 行をフィルタリング(集計前)
  3. GROUP BY: グループ化
  4. HAVING: グループをフィルタリング(集計後)
  5. SELECT: 表示する列を選択

WHERE はグループ化の前に実行されるため、集計結果を知ることができない。 一方、HAVING はグループ化の後に実行されるため、集計結果に基づいてフィルタリングが可能である。

まとめ

  • WHERE: 集計 の行を絞り込む。
  • HAVING: 集計 のグループを絞り込む。

「集計結果に対して条件を指定したい場合は HAVING」と覚えておけば間違いない。