SQLで日付を扱う!PostgreSQLとMySQLでの「今日・今月・直近7日間」フィルターの書き方

こんにちは、さるまりんです🐒

これまでもやってきましたが、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 <を基本にしておくのが安心かな。

この辺りを注意しながらもっとわかりやすいコードを書いていきたいです。

読んでくださってありがとうございました。

それではまた!