こんにちは、さるまりんです🐒
これまでもやってきましたが、SQLで日付のフィルターをかける処理はとてもよく登場しますよね。
たとえば…
- 今日のデータだけ見たい
- 今月の集計を出したい
- 直近7日間の分析したい
でも、日付関数の書き方って、使っているDBごとにちょっとずつ違います。
今回は、PostgreSQLとMySQLを中心に、「今日」「今月」「直近7日間」の絞り込み方法を比べながら紹介します。
「今日」のデータを取得する
PostgreSQL の場合
SELECT * FROM orders
WHERE order_date::date = CURRENT_DATE;
::date
で時刻を落として、日付だけを比較しますCURRENT_DATE
はその日の0時0分0秒と等しい値です
MySQL の場合
SELECT * FROM orders
WHERE DATE(order_date) = CURDATE();
DATE()
関数で時刻を切り落としますCURDATE()
は今日の日付(時刻なし)を返します
補足(時刻が含まれる場合の注意)
order_date >= CURDATE()
のように比較すると、今日の0時以降のデータになります- ただし
=
を使う場合は、時刻部分の除去(キャストや関数)が必要です
「今月」のデータを取得する
PostgreSQL の場合
SELECT * FROM orders
WHERE DATE_TRUNC('month', order_date) = DATE_TRUNC('month', CURRENT_DATE);
DATE_TRUNC('month', ...)
で月初に揃えます (month
で月を指定)- 同じ月なら、トランケートした日付同士で一致します
MySQL の場合
SELECT * FROM orders
WHERE DATE_FORMAT(order_date, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m');
DATE_FORMAT(..., '%Y-%m')
で"2024-06"
のように月単位で比較しています
補足
- PostgreSQLの方が日付型のまま扱えます (集計しやすい?)
- MySQLは文字列比較になるので、インデックスが効きにくいこともあります
「直近7日間」のデータを取得する
PostgreSQL の場合
SELECT * FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '7 days';
INTERVAL
を使って7日前の日付を作成しています
MySQL の場合
SELECT * FROM orders
WHERE order_date >= CURDATE() - INTERVAL 7 DAY;
- こちらも同じくです。 CURDATE()をもとに INTERVALを使って7日前の日付を作成しています (違いに注意)
Oracle を使っている場合の注意点も
- Oracleでは
SYSDATE
を使います(CURRENT_DATE
はタイムゾーンに依存します) - 日付の比較には
TRUNC()
を使って時刻を落とします
例:今日のデータを取得
SELECT * FROM orders
WHERE TRUNC(order_date) = TRUNC(SYSDATE);
例:今月のデータ(ちょっとだけ複雑)
SELECT * FROM orders
WHERE TRUNC(order_date, 'MM') = TRUNC(SYSDATE, 'MM');
BETWEEN vs >= AND < の違い
「月内のデータを取得したい」とき、次の2つの書き方がよく登場します:
-- A: BETWEEN で月初〜月末を指定
WHERE order_date BETWEEN '2024-06-01' AND '2024-06-30';
-- B: >= と < を使う
WHERE order_date >= '2024-06-01' AND order_date < '2024-07-01';
- Aの方法は 月末日付のミスや時刻による取りこぼしが起きやすい
- Bの方法は 時刻を含む比較に向いています(特に
timestamp
型を使用時)
個人的なイメージですが、Bの>= AND <
パターンがより使うと思います。(安全?)
まとめです
表にしてみました。
絞り込み | PostgreSQL | MySQL |
今日 | order_date::date = CURRENT_DATE |
DATE(order_date) = CURDATE() |
今月 | DATE_TRUNC('month', order_date) = DATE_TRUNC('month', CURRENT_DATE) |
DATE_FORMAT(order_date, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m') |
直近7日間 | order_date >= CURRENT_DATE - INTERVAL '7 days' |
order_date >= CURDATE() - INTERVAL 7 DAY |
RDBごとに日付関数の違いはあるけれど、目的は同じです!
キャストや関数の扱いに注意すれば、より安全で読みやすいSQLが書けると思います。
日付範囲の比較には >= AND <
を基本にしておくのが安心かな。
この辺りを注意しながらもっとわかりやすいコードを書いていきたいです。
読んでくださってありがとうございました。
それではまた!