日付関数の活用

日付関数の活用 とは

SQLで日付関数を活用する方法を学びます。日付データの操作をマスターしましょう。本レッスンでは、日付関数の活用 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

アプリには必ず「いつ」の情報が付いて回ります。投稿日時、購入日、ログイン履歴、期限、誕生日。日付の扱いを誤ると、月跨ぎの集計でズレが出たり、タイムゾーンの違いで日数が一日変わったりします。日付関数を正しく使えるかどうかが、レポートやバッチ処理の精度をそのまま決めます。

また、現場では「今日の売上」「今週の新規ユーザー」「先月の解約数」のような、相対的な日付条件が頻繁に登場します。CURRENT_DATEINTERVALto_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 / TiDBPostgreSQL では関数名が少しずつ違います。本レッスンと演習画面では PGlite 上で動く PostgreSQL 互換の文法に揃えます。

処理の流れ

diagram (will load when visible)

日付関数は 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 で済ませてしまうことも多いです。

タイムゾーンに注意

PostgreSQLTIMESTAMP / 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 つができることを確認しましょう。

  1. 日付関数 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  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');

期待される出力

idcustomer_nameamountordered_at
5伊藤30002026-05-02
6渡辺220002026-05-08
7山田75002026-05-15
8中村98002026-05-18

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...