NEKO BLOG

SQLでSELECTするレコードの最大値をWHERE文に指定したい

MySQL経歴が浅い私としては、知らない人すぎて怖いイメージのコマンドがあります。 その名もHAVINGさん。 どんな時に使えばいいのかのイメージもつきづらく、とっつきづらい苦手なタイプの人でした。

それが今回、思わぬところで活躍しれくれて、案外いいやつじゃん。 そう思えたシーンがあったので共有します。

先に結論

HAVINGさんは、集計結果に条件をかけるときに活躍してくれます。

単純に行単位で条件をかけるときはWHEREさんでいいのですが、 WHEREで絞った後のグループ単位でさらに条件をかける。こんなことができます。

やりたかったこと

こんなテーブル構成があります。

とある映画(Movie)があり、その上映時間予約枠(ReserveSlot)、予約をとったユーザー(User)が紐づいています。

ここから1月中にずっと上映されていた映画をみたユーザー一覧と映画情報を取りたいとします。

まず1月中に1回でも上映された映画だけなら、これで抽出できます。

sql

SELECT DISTINCT mo.*
FROM Movie mo
INNER JOIN ReserveSlot rs ON rs.MOVIE_ID = mo.ID
WHERE rs.RESERVE_DATE BETWEEN '2026-01-01' AND '2026-01-31';

ただこれ、「ずっと上映されていた」映画ではないんですよね。 1月中「ずっと」をSQLで表現するなら、 RESERVE_DATEが1月1日以前に始まっていて、1月31日以降に終わっている。

WEHRE文は行にしか条件をかけられないので、最大・最小の判定はできません。 ここで登場するのがHAVINGさん。

映画とユーザーでグルーピングした情報に、HAVINGで1月中にずっと上映されていたかを集計することができます。

sql

SELECT DISTINCT mo.*, u.*
FROM Movie mo
INNER JOIN ReserveSlot rs ON rs.MOVIE_ID = mo.ID
INNER JOIN User u ON rs.USER_ID = u.ID
GROUP BY mo.ID, u.ID
HAVING MIN(rs.RESERVE_DATE) <= '2026-01-01'
   AND MAX(rs.RESERVE_DATE) >= '2026-01-31';

終わりに

WHEREとHAVINGの違いは、行単位で条件をかけるか、グルーピングしたものに条件をかけるか。

それだけではありますが、問題は仕様の日本語の難解さにもあるような気がしてなりません。。

というわけで、HAVINGさんのご紹介でした。