SQLの日付・時刻を完全理解!基本操作と活用テクニックをやさしく解説

データベース・SQL

データベースを使っていて、「今日のデータだけ取得したい」「日付で並べ替えたい」「1週間以内の注文を抽出したい」といった場面はよくあります。

そんな時に欠かせないのが、SQLでの日付・時刻の扱いです。

この記事では、SQLにおける日付・時刻データの基本から、比較、抽出、フォーマット変換のテクニックまで、初心者にも分かりやすく解説します。

スポンサーリンク

日付・時刻のデータ型を知ろう

主要なデータ型

SQLでは、日付や時刻を扱うために以下のデータ型が用意されています。

DATE型:日付のみ

  • 保存形式:YYYY-MM-DD
  • :2025-06-02
  • 用途:誕生日、開始日、終了日など

TIME型:時刻のみ

  • 保存形式:HH:MM:SS
  • :14:30:00
  • 用途:営業時間、開店時刻など

DATETIME型:日付と時刻

  • 保存形式:YYYY-MM-DD HH:MM:SS
  • :2025-06-02 14:30:00
  • 用途:注文日時、更新日時など

TIMESTAMP型:タイムスタンプ

  • 特徴:UNIX時間をベースにした日時
  • 用途:レコードの作成・更新時刻の自動記録

テーブル作成の例

-- MySQL の例
CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_name VARCHAR(100),
    order_date DATETIME,
    delivery_date DATE,
    order_time TIME,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- データの挿入例
INSERT INTO orders (id, customer_name, order_date, delivery_date, order_time) 
VALUES (1, '田中太郎', '2025-06-02 14:30:00', '2025-06-05', '14:30:00');

データ型の選び方

  • 日付だけが必要:DATE型
  • 時刻だけが必要:TIME型
  • 日付と時刻の両方が必要:DATETIME型
  • 自動で現在時刻を記録したい:TIMESTAMP型

ポイント

  • データ型によって保存できる情報が変わる
  • 目的に応じて適切なデータ型を選択
  • 文字列ではなく専用のデータ型を使うことが重要

まずはデータ型を正しく理解することで、適切な比較や演算が可能になります。次は、よく使う日付関数を紹介します。

よく使う日付・時刻関数を覚えよう

現在の日付・時刻を取得する関数

-- 現在の日付と時刻を取得
SELECT NOW();
-- 結果例:2025-06-03 15:45:30

-- 現在の日付のみを取得
SELECT CURDATE();
-- 結果例:2025-06-03

-- 現在の時刻のみを取得
SELECT CURTIME();
-- 結果例:15:45:30

日付の一部を抽出する関数

-- DATETIME型から日付部分だけを抽出
SELECT DATE('2025-06-03 15:45:30');
-- 結果:2025-06-03

-- 年を抽出
SELECT YEAR('2025-06-03');
-- 結果:2025

-- 月を抽出
SELECT MONTH('2025-06-03');
-- 結果:6

-- 日を抽出
SELECT DAY('2025-06-03');
-- 結果:3

-- 曜日を抽出(1=日曜日、2=月曜日...)
SELECT DAYOFWEEK('2025-06-03');
-- 結果:3(火曜日)

日付の差を計算する関数

-- 日付の差を日数で計算
SELECT DATEDIFF('2025-06-10', '2025-06-01');
-- 結果:9

-- 今日から指定日まであと何日か
SELECT DATEDIFF('2025-12-31', CURDATE());

-- 年齢を計算(誕生日から今日まで)
SELECT FLOOR(DATEDIFF(CURDATE(), '1990-05-15') / 365.25) AS age;

日付を加算・減算する関数

-- 3日後の日付
SELECT DATE_ADD(CURDATE(), INTERVAL 3 DAY);

-- 1週間前の日付
SELECT DATE_SUB(CURDATE(), INTERVAL 1 WEEK);

-- 2ヶ月後の日付
SELECT DATE_ADD('2025-06-03', INTERVAL 2 MONTH);

-- 1年前の日付
SELECT DATE_SUB('2025-06-03', INTERVAL 1 YEAR);

よく使う時間単位

-- 様々な時間単位での加算例
SELECT DATE_ADD(NOW(), INTERVAL 1 HOUR);    -- 1時間後
SELECT DATE_ADD(NOW(), INTERVAL 30 MINUTE); -- 30分後
SELECT DATE_ADD(NOW(), INTERVAL 1 WEEK);    -- 1週間後
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH);   -- 3ヶ月後
SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR);    -- 1年後

ポイント

  • NOW()、CURDATE()は動的な値(実行時の現在時刻)
  • INTERVAL を使って柔軟に日付計算
  • DATEDIFF で期間計算が簡単にできる

関数を活用すれば、日付を柔軟に扱えます。

次は、日付を条件に使った検索例を見てみましょう。

日付で条件を指定してデータを抽出しよう

特定の日付でデータを抽出

-- 今日の注文だけを取得
SELECT * FROM orders 
WHERE DATE(order_date) = CURDATE();

-- 2025年6月3日の注文だけを取得
SELECT * FROM orders 
WHERE DATE(order_date) = '2025-06-03';

-- 今月の注文を取得
SELECT * FROM orders 
WHERE YEAR(order_date) = YEAR(NOW()) 
  AND MONTH(order_date) = MONTH(NOW());

期間を指定してデータを抽出

-- 直近7日間の注文
SELECT * FROM orders 
WHERE order_date >= DATE_SUB(NOW(), INTERVAL 7 DAY);

-- 先月の注文
SELECT * FROM orders 
WHERE order_date >= DATE_SUB(DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY), INTERVAL 1 MONTH)
  AND order_date < DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY);

-- より簡単な先月の書き方
SELECT * FROM orders 
WHERE YEAR(order_date) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH))
  AND MONTH(order_date) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH));

範囲指定での抽出

-- 2025年1月1日から6月30日までの注文
SELECT * FROM orders 
WHERE order_date BETWEEN '2025-01-01' AND '2025-06-30 23:59:59';

-- 3ヶ月以内の注文
SELECT * FROM orders 
WHERE order_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH);

-- 1年以上前の古いデータ
SELECT * FROM orders 
WHERE order_date < DATE_SUB(NOW(), INTERVAL 1 YEAR);

時刻を含む条件指定

-- 今日の午前中の注文
SELECT * FROM orders 
WHERE DATE(order_date) = CURDATE() 
  AND TIME(order_date) < '12:00:00';

-- 営業時間内(9:00-18:00)の注文
SELECT * FROM orders 
WHERE TIME(order_date) BETWEEN '09:00:00' AND '18:00:00';

-- 週末の注文
SELECT * FROM orders 
WHERE DAYOFWEEK(order_date) IN (1, 7);  -- 1=日曜日, 7=土曜日

便利な条件指定のパターン

-- 今年のデータ
SELECT * FROM orders WHERE YEAR(order_date) = YEAR(NOW());

-- 今四半期のデータ
SELECT * FROM orders 
WHERE QUARTER(order_date) = QUARTER(NOW()) 
  AND YEAR(order_date) = YEAR(NOW());

-- 誕生日が今月の顧客
SELECT * FROM customers 
WHERE MONTH(birthday) = MONTH(NOW());

ポイント

  • DATE()関数で日付部分のみを比較
  • BETWEEN で範囲指定が簡単
  • INTERVAL を使った相対的な期間指定が便利

日付条件を活用すれば、動的なデータ抽出も可能になります。次は、日付による並び替えやグループ化を紹介します。

ORDER BYとGROUP BYで日付を活用しよう

日付での並び替え(ORDER BY)

-- 注文日の新しい順に並べる
SELECT customer_name, order_date FROM orders 
ORDER BY order_date DESC;

-- 注文日の古い順に並べる
SELECT customer_name, order_date FROM orders 
ORDER BY order_date ASC;

-- 複数の条件で並び替え(日付→時刻順)
SELECT customer_name, order_date FROM orders 
ORDER BY DATE(order_date) DESC, TIME(order_date) ASC;

日付でのグループ化(GROUP BY)

日別の集計

-- 日別の注文件数
SELECT 
    DATE(order_date) AS order_day,
    COUNT(*) AS order_count
FROM orders 
GROUP BY DATE(order_date)
ORDER BY order_day DESC;

月別の集計

-- 月別の注文件数
SELECT 
    DATE_FORMAT(order_date, '%Y-%m') AS order_month,
    COUNT(*) AS order_count,
    SUM(amount) AS total_amount
FROM orders 
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY order_month DESC;

-- より読みやすい月別集計
SELECT 
    YEAR(order_date) AS year,
    MONTH(order_date) AS month,
    COUNT(*) AS order_count
FROM orders 
GROUP BY YEAR(order_date), MONTH(order_date)
ORDER BY year DESC, month DESC;

曜日別の集計

-- 曜日別の注文件数
SELECT 
    CASE DAYOFWEEK(order_date)
        WHEN 1 THEN '日曜日'
        WHEN 2 THEN '月曜日'
        WHEN 3 THEN '火曜日'
        WHEN 4 THEN '水曜日'
        WHEN 5 THEN '木曜日'
        WHEN 6 THEN '金曜日'
        WHEN 7 THEN '土曜日'
    END AS day_of_week,
    COUNT(*) AS order_count
FROM orders 
GROUP BY DAYOFWEEK(order_date)
ORDER BY DAYOFWEEK(order_date);

時間帯別の集計

-- 時間帯別の注文件数
SELECT 
    HOUR(order_date) AS hour,
    COUNT(*) AS order_count
FROM orders 
GROUP BY HOUR(order_date)
ORDER BY hour;

-- 時間帯をグループ化
SELECT 
    CASE 
        WHEN HOUR(order_date) BETWEEN 6 AND 11 THEN '午前'
        WHEN HOUR(order_date) BETWEEN 12 AND 17 THEN '午後'
        WHEN HOUR(order_date) BETWEEN 18 AND 23 THEN '夜'
        ELSE '深夜・早朝'
    END AS time_period,
    COUNT(*) AS order_count
FROM orders 
GROUP BY time_period
ORDER BY time_period;

結果のイメージ(月別集計)

order_month | order_count | total_amount
------------|-------------|-------------
2025-06     | 45          | 125000
2025-05     | 38          | 98000
2025-04     | 52          | 142000

応用的な集計例

-- 四半期別の売上推移
SELECT 
    YEAR(order_date) AS year,
    QUARTER(order_date) AS quarter,
    COUNT(*) AS order_count,
    AVG(amount) AS avg_amount
FROM orders 
GROUP BY YEAR(order_date), QUARTER(order_date)
ORDER BY year DESC, quarter DESC;

-- 週別の売上(月曜日始まり)
SELECT 
    DATE_SUB(order_date, INTERVAL (DAYOFWEEK(order_date) + 5) % 7 DAY) AS week_start,
    COUNT(*) AS order_count
FROM orders 
GROUP BY week_start
ORDER BY week_start DESC;

ポイント

  • GROUP BY で様々な時間単位での集計が可能
  • DATE_FORMAT で柔軟な日付表示
  • CASE文で読みやすい表示に変換

データの傾向分析や可視化に日付集計は不可欠です。

最後に、日付フォーマットの変換方法も見てみましょう。

日付フォーマットを自由に変換しよう

MySQL での日付フォーマット

DATE_FORMAT()関数を使って、日付の表示形式を自由に変えられます。

よく使うフォーマット指定子

指定子意味
%Y4桁の年2025
%y2桁の年25
%m2桁の月(01-12)06
%c月(1-12)6
%d2桁の日(01-31)03
%e日(1-31)3
%H24時間形式の時(00-23)15
%h12時間形式の時(01-12)03
%i分(00-59)45
%s秒(00-59)30
%W曜日名Tuesday
%w曜日番号(0=日曜日)2

実際の使用例

-- 基本的なフォーマット
SELECT DATE_FORMAT(order_date, '%Y/%m/%d') AS japanese_date
FROM orders;
-- 結果例:2025/06/03

-- 時刻も含めたフォーマット
SELECT DATE_FORMAT(order_date, '%Y年%m月%d日 %H時%i分') AS full_datetime
FROM orders;
-- 結果例:2025年06月03日 15時45分

-- 曜日を含むフォーマット
SELECT DATE_FORMAT(order_date, '%Y/%m/%d (%W)') AS date_with_day
FROM orders;
-- 結果例:2025/06/03 (Tuesday)

-- 12時間形式の時刻
SELECT DATE_FORMAT(order_date, '%Y/%m/%d %h:%i %p') AS twelve_hour
FROM orders;
-- 結果例:2025/06/03 03:45 PM

PostgreSQL での日付フォーマット

TO_CHAR()関数を使用します。

よく使うフォーマット指定子

指定子意味
YYYY4桁の年2025
YY2桁の年25
MM2桁の月06
DD2桁の日03
HH2424時間形式の時15
HH1212時間形式の時03
MI45
SS30
DAY曜日名(フル)TUESDAY
DY曜日名(省略)TUE

実際の使用例

-- PostgreSQL の例
SELECT TO_CHAR(order_date, 'YYYY/MM/DD') AS formatted_date
FROM orders;
-- 結果例:2025/06/03

SELECT TO_CHAR(order_date, 'YYYY年MM月DD日 HH24:MI') AS japanese_datetime
FROM orders;
-- 結果例:2025年06月03日 15:45

実用的なフォーマット例

-- レポート用の見やすい日付
SELECT 
    customer_name,
    DATE_FORMAT(order_date, '%Y年%m月%d日') AS 注文日,
    DATE_FORMAT(order_date, '%H:%i') AS 注文時刻
FROM orders;

-- CSV出力用の形式
SELECT 
    customer_name,
    DATE_FORMAT(order_date, '%Y-%m-%d %H:%i:%s') AS order_datetime
FROM orders;

-- 月次レポート用
SELECT 
    DATE_FORMAT(order_date, '%Y年%m月') AS 対象月,
    COUNT(*) AS 注文件数
FROM orders 
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 対象月 DESC;

文字列から日付への変換

-- 文字列をDATE型に変換
SELECT STR_TO_DATE('2025-06-03', '%Y-%m-%d') AS converted_date;

-- 様々な形式の文字列を変換
SELECT STR_TO_DATE('2025年6月3日', '%Y年%m月%d日') AS japanese_format;
SELECT STR_TO_DATE('06/03/2025', '%m/%d/%Y') AS us_format;

ポイント

  • データベースごとに関数名が異なる
  • フォーマット指定子を覚えると表示を自由に制御可能
  • レポート出力時には読みやすい形式に変換
  • 文字列からの変換も可能

フォーマット変換を使えば、ユーザーに見せる日付もわかりやすく整形できます。

まとめ

SQLでの日付・時刻の扱いは、実務で欠かせない技術です。

覚えるべきポイント

  • データ型の理解:DATE、TIME、DATETIME、TIMESTAMPの使い分け
  • 基本関数:NOW()、CURDATE()、DATE_ADD()、DATEDIFF()など
  • 条件指定:WHERE句での期間指定や日付比較
  • 集計・並び替え:GROUP BYとORDER BYでの日付活用
  • フォーマット変換:見やすい表示形式への変換

実務での活用場面

  • 売上分析:日別・月別・四半期別の売上推移
  • ユーザー分析:登録日、最終ログイン日での分析
  • 在庫管理:入荷日、賞味期限での管理
  • レポート作成:期間指定での各種集計レポート

よく使われるパターン

-- 今月の売上
SELECT SUM(amount) FROM sales 
WHERE MONTH(sale_date) = MONTH(NOW()) 
  AND YEAR(sale_date) = YEAR(NOW());

-- 直近30日のアクティブユーザー
SELECT COUNT(DISTINCT user_id) FROM access_logs 
WHERE access_date >= DATE_SUB(NOW(), INTERVAL 30 DAY);

-- 年齢別の顧客分析
SELECT 
    FLOOR(DATEDIFF(NOW(), birthday) / 365.25) AS age,
    COUNT(*) as customer_count
FROM customers 
GROUP BY age 
ORDER BY age;

コメント

タイトルとURLをコピーしました