データベースの日次バッチ処理やレポート生成で「前日のデータだけを取得したい」という場面は非常によくあります。
しかし、日付型カラムに時刻が含まれていると単純な比較では上手くいきません。本記事では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変換を忘れずに