【SQL】前日のデータを取得する方法【MySQL・PostgreSQL・SQL Server・Oracle】

データベースの日次バッチ処理やレポート生成で「前日のデータだけを取得したい」という場面は非常によくあります。

しかし、日付型カラムに時刻が含まれていると単純な比較では上手くいきません。本記事ではMySQL・PostgreSQL・SQL Server・Oracleの4種類のRDBMS別に正しい書き方を紹介します。

この記事で学べること:4種のDBMS別・前日データ取得SQL・インデックスを活用した高速化・タイムゾーン対応
スポンサーリンク

MySQLで前日のデータを取得する

MySQLではDATE()関数で日付部分を切り出し、CURDATE() - INTERVAL 1 DAYと比較します。

-- 基本形
SELECT *
FROM orders
WHERE DATE(order_date) = CURDATE() - INTERVAL 1 DAY;

-- 範囲指定(インデックスが効きやすい書き方)
SELECT *
FROM orders
WHERE order_date >= CURDATE() - INTERVAL 1 DAY
  AND order_date <  CURDATE();
パフォーマンス改善:DATE()関数をカラムに適用するとインデックスが使えなくなります。範囲指定(BETWEEN / >= and <)の書き方の方が高速です。

PostgreSQLで前日のデータを取得する

-- 基本形
SELECT *
FROM orders
WHERE order_date::date = CURRENT_DATE - INTERVAL '1 day';

-- 範囲指定(インデックス活用)
SELECT *
FROM orders
WHERE order_date >= (CURRENT_DATE - INTERVAL '1 day')
  AND order_date <   CURRENT_DATE;

SQL Serverで前日のデータを取得する

-- 基本形
SELECT *
FROM orders
WHERE CAST(order_date AS DATE) = CAST(GETDATE() AS DATE) - 1;

-- 範囲指定(インデックス活用)
SELECT *
FROM orders
WHERE order_date >= CAST(CONVERT(date, GETDATE() - 1) AS DATETIME)
  AND order_date <  CAST(CONVERT(date, GETDATE())     AS DATETIME);

Oracleで前日のデータを取得する

-- 基本形
SELECT *
FROM orders
WHERE TRUNC(order_date) = TRUNC(SYSDATE) - 1;

-- 範囲指定(インデックス活用)
SELECT *
FROM orders
WHERE order_date >= TRUNC(SYSDATE) - 1
  AND order_date <  TRUNC(SYSDATE);
OracleのTRUNC:TRUNC(date)は時刻を00:00:00にリセットします。カラムにTRUNCを適用するとインデックスが使えなくなるため、範囲指定の書き方を優先してください。

DBMS別・前日データ取得まとめ表

DBMS 現在日付の取得 推奨の書き方
MySQL CURDATE() order_date >= CURDATE()-1 AND < CURDATE()
PostgreSQL CURRENT_DATE order_date >= CURRENT_DATE-1 AND < CURRENT_DATE
SQL Server GETDATE() CAST(GETDATE()-1 AS DATE) ≤ date < CAST(GETDATE() AS DATE)
Oracle TRUNC(SYSDATE) date >= TRUNC(SYSDATE)-1 AND < TRUNC(SYSDATE)

よくある質問(FAQ)

Q. 前々日や3日前のデータを取得するにはどうすればよいですか?
A. MySQLならCURDATE() - INTERVAL 2 DAYで前々日、INTERVAL 7 DAYで1週間前になります。OracleはTRUNC(SYSDATE) - 2のように数値を変えるだけです。
Q. タイムゾーンを考慮した前日データの取得方法は?
A. UTCで保存されているデータをJST(日本時間)で前日取得する場合はMySQL: DATE(CONVERT_TZ(order_date,'+00:00','+09:00'))のように変換します。PostgreSQL: order_date AT TIME ZONE 'Asia/Tokyo'を使います。
Q. インデックスが使われているかどうか確認するにはどうすればよいですか?
A. MySQLではEXPLAIN SELECT ...を実行し、typeがrangeまたはrowsが少ない場合はインデックスが効いています。ALL(フルスキャン)になっていれば関数をカラムに適用している可能性があります。

まとめ

  • 日付カラムに時刻が含まれる場合は範囲指定(>= 前日0時 AND < 当日0時)が最適
  • カラムに関数(DATE()・TRUNC()など)を適用するとインデックスが効かなくなる
  • 4種のDBMS(MySQL・PostgreSQL・SQL Server・Oracle)で書き方が異なる
  • タイムゾーンがある環境ではUTC→JST変換を忘れずに