日付関数の活用
日付関数の活用 とは
SQLで日付関数を活用する方法を学びます。日付データの操作をマスターしましょう。本レッスンでは、日付関数の活用 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
なぜ重要か
アプリには必ず「いつ」の情報が付いて回ります。投稿日時、購入日、ログイン履歴、期限、誕生日。日付の扱いを誤ると、月跨ぎの集計でズレが出たり、タイムゾーンの違いで日数が一日変わったりします。日付関数を正しく使えるかどうかが、レポートやバッチ処理の精度をそのまま決めます。
また、現場では「今日の売上」「今週の新規ユーザー」「先月の解約数」のような、相対的な日付条件が頻繁に登場します。CURRENT_DATE、INTERVAL、to_char といった PostgreSQL 系の日付表現の使い分けを覚えておくと、ハードコード日付を書かずに済むようになります。
主な日付関数
SQL クエリ
CURRENT_DATE -- 今日 (例 '2026-05-19')
NOW() -- 今この瞬間 (日時)
col::date -- 日時から日付部分だけ取り出す
EXTRACT(YEAR FROM col) -- 年を取り出す
col + INTERVAL '7 days' -- 7日後
col1::date - col2::date -- 日数差
to_char(col, 'YYYY-MM-DD') -- 表示用に整形MySQL / TiDB と PostgreSQL では関数名が少しずつ違います。本レッスンと演習画面では PGlite 上で動く PostgreSQL 互換の文法に揃えます。
処理の流れ
日付関数は SELECT の列としても、WHERE の条件式としても使えます。WHERE で日付関数を使うとインデックスが効かなくなるケースがあるので注意します。
代表例
例 1 は、特定の月のデータを抽出するケースです。
SQL クエリ
SELECT id, title, published_at
FROM articles
WHERE EXTRACT(YEAR FROM published_at) = 2026
AND EXTRACT(MONTH FROM published_at) = 5;わかりやすい書き方ですが、EXTRACT(YEAR FROM 列) を WHERE に書くと インデックスが効きません。次のように範囲指定すると、インデックスが効きやすくなります。
SQL クエリ
SELECT id, title, published_at
FROM articles
WHERE published_at >= '2026-05-01'
AND published_at < '2026-06-01';本番では下の書き方を選びます。可読性は少し落ちますが、性能差が大きいです。
例 2 は、直近 7 日間のデータを取り出すケースです。
SQL クエリ
SELECT id, title, published_at
FROM articles
WHERE published_at >= CURRENT_DATE - INTERVAL '7 days';CURRENT_DATE - INTERVAL '7 days' で「今日から 7 日前」を求め、それ以降に投稿された記事を抽出しています。+ INTERVAL '7 days' を使えば「7 日後まで」のような期限切れチェックにも応用できます。これらは INTERVAL キーワードと組み合わせて期間を指定します。
例 3 は、日付をフォーマットして表示用に整えるケースです。
SQL クエリ
SELECT id, title,
to_char(published_at, 'YYYY年MM月DD日') AS japan_date
FROM articles
ORDER BY published_at DESC;to_char でアプリ側に渡しやすい形に整形できます。アプリ層でフォーマットするのが基本ですが、レポート系のクエリでは SQL で済ませてしまうことも多いです。
タイムゾーンに注意
PostgreSQLのTIMESTAMP/timestamptzは型の選び方でタイムゾーンの扱いが変わります。アプリが UTC 保存・JST 表示を採用しているなら、表示・集計時にcol AT TIME ZONE 'Asia/Tokyo'のように変換してから集計すると安全です。タイムゾーンは「DB 保存時に UTC、アプリで JST に変換」が業界の鉄板ルールです。
WHERE 句のインデックス友好な書き方
WHERE YEAR(date_col) = 2026のように列を関数で包むと、インデックスが使われずフルスキャンになります。WHERE date_col >= '2026-01-01' AND date_col < '2027-01-01'のように範囲指定で書き換えると、B-tree インデックスが効きます。性能チューニングの定番ポイントです。
月初・月末を求めるイディオム
月次レポートを作るときに「対象月の月初から翌月の月初まで」を範囲指定する場面が多くあります。PostgreSQL なら次のように書きます。
SQL クエリ
-- 2026 年 5 月の集計
SELECT SUM(amount) AS total
FROM orders
WHERE ordered_at >= '2026-05-01'
AND ordered_at < DATE '2026-05-01' + INTERVAL '1 month';この形は月によって 28 日・30 日・31 日と日数が変わっても破綻しません。月末日をハードコードするより安全です。
まとめ
- CURRENT_DATE / NOW / EXTRACT が基礎
+ INTERVAL/- INTERVALで相対日付を計算できる- 日付同士の差分で日数差を取得
to_charで表示用に整形- WHERE で日付関数を使うとインデックスが効かない。範囲指定で書き換える
- タイムゾーンは UTC 保存・表示時変換が鉄則
- 月次集計は「翌月の月初」までを
<で指定するイディオムが安全
次のレッスン
次は データ取得チャレンジ です。SQLの知識を試すデータ取得チャレンジ!クイズ形式で実践力を高めましょう。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 日付関数 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 日付関数 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
テーブル構造
schema.sql
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_name VARCHAR(50) NOT NULL,
amount INT NOT NULL,
ordered_at DATE NOT NULL
);
INSERT INTO orders (id, customer_name, amount, ordered_at) VALUES
(1, '田中', 5000, '2026-03-10'),
(2, '佐藤', 12000, '2026-04-05'),
(3, '鈴木', 8000, '2026-04-15'),
(4, '高橋', 15000, '2026-04-28'),
(5, '伊藤', 3000, '2026-05-02'),
(6, '渡辺', 22000, '2026-05-08'),
(7, '山田', 7500, '2026-05-15'),
(8, '中村', 9800, '2026-05-18');期待される出力
| id | customer_name | amount | ordered_at |
|---|---|---|---|
| 5 | 伊藤 | 3000 | 2026-05-02 |
| 6 | 渡辺 | 22000 | 2026-05-08 |
| 7 | 山田 | 7500 | 2026-05-15 |
| 8 | 中村 | 9800 | 2026-05-18 |