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さんのご紹介でした。