Oracle の INTERVAL データ型は「期間」を表す専用の型です。DATE の差(date2 - date1)が数値になる Oracle の仕様と違い、INTERVAL を使うと年月・日時分秒という期間の意味を型として保持したまま計算できます。
勤怠計算・SLA(サービスレベル契約)の残時間・契約期限の管理など、期間を正確に扱いたい場面で非常に便利です。
この記事でわかること
- INTERVAL YEAR TO MONTH と INTERVAL DAY TO SECOND の書き方と精度指定
- INTERVAL リテラルの構文(INTERVAL ‘3-6’ YEAR TO MONTH など)
- NUMTOYMINTERVAL / NUMTODSINTERVAL で数値を INTERVAL に変換する方法
- DATE・TIMESTAMP への加算・減算
- INTERVAL 同士の演算(加算・減算・スカラー倍)
- EXTRACT で INTERVAL から特定の要素を取り出す方法
INTERVAL データ型の2種類
| 型 | 表す期間 | 書き方の例 | 用途 |
|---|---|---|---|
INTERVAL YEAR[(y)] TO MONTH |
年・月 | INTERVAL ‘3-6’ YEAR TO MONTH(3年6ヶ月) | 契約期間・年齢・勤続年数 |
INTERVAL DAY[(d)] TO SECOND[(s)] |
日・時・分・秒(小数秒) | INTERVAL ‘2 10:30:00’ DAY TO SECOND(2日10時間30分) | 所要時間・SLA・遅延計算 |
括弧内の数字は先頭フィールドの精度です。INTERVAL YEAR(4) TO MONTH は年を4桁まで(最大 9999年)格納できます。デフォルトは YEAR(2)(最大 99年)・DAY(2)(最大 99日)です。
INTERVAL YEAR TO MONTH の使い方
INTERVAL YEAR TO MONTH のリテラルと列定義
-- INTERVAL リテラルの書き方: INTERVAL '年-月' YEAR TO MONTH
SELECT INTERVAL '3-6' YEAR TO MONTH FROM DUAL; -- 3年6ヶ月
SELECT INTERVAL '0-9' YEAR TO MONTH FROM DUAL; -- 9ヶ月
SELECT INTERVAL '10' YEAR FROM DUAL; -- 10年(YEAR のみ)
SELECT INTERVAL '6' MONTH FROM DUAL; -- 6ヶ月(MONTH のみ)
-- 列定義(契約期間テーブルの例)
CREATE TABLE contracts (
contract_id NUMBER PRIMARY KEY,
start_date DATE,
duration INTERVAL YEAR(3) TO MONTH, -- 最大 999年
contract_name VARCHAR2(100)
);
INSERT INTO contracts VALUES (1, DATE '2024-04-01', INTERVAL '2-6' YEAR TO MONTH, '2年6ヶ月契約');
INSERT INTO contracts VALUES (2, DATE '2024-04-01', INTERVAL '1' YEAR, '1年契約');
INSERT INTO contracts VALUES (3, DATE '2024-04-01', INTERVAL '6' MONTH, '6ヶ月契約');
-- DATE + INTERVAL YEAR TO MONTH = DATE
SELECT
contract_name,
start_date,
duration,
start_date + duration AS end_date -- 契約終了日
FROM contracts;
-- NUMTOYMINTERVAL で数値を INTERVAL に変換する
SELECT NUMTOYMINTERVAL(18, 'MONTH') FROM DUAL; -- 18ヶ月 → INTERVAL '1-6'
SELECT NUMTOYMINTERVAL(2, 'YEAR') FROM DUAL; -- 2年 → INTERVAL '2-0'
-- ADD_MONTHS との比較: INTERVAL は日付の意味を持つ
SELECT SYSDATE + NUMTOYMINTERVAL(3, 'MONTH') FROM DUAL; -- 3ヶ月後
SELECT ADD_MONTHS(SYSDATE, 3) FROM DUAL; -- 同等
INTERVAL DAY TO SECOND の使い方
INTERVAL DAY TO SECOND のリテラルと時間計算
-- INTERVAL リテラルの書き方: INTERVAL '日 時:分:秒.小数秒' DAY TO SECOND
SELECT INTERVAL '2 10:30:00' DAY TO SECOND FROM DUAL; -- 2日10時間30分
SELECT INTERVAL '0 08:00:00' DAY TO SECOND FROM DUAL; -- 8時間
SELECT INTERVAL '0 00:01:30' DAY TO SECOND FROM DUAL; -- 1分30秒
SELECT INTERVAL '1.5' DAY FROM DUAL; -- 1.5日(= 36時間)
SELECT INTERVAL '120' MINUTE FROM DUAL; -- 120分
SELECT INTERVAL '3600' SECOND FROM DUAL; -- 3600秒
-- DAY(3) TO SECOND(6): 最大 999日・マイクロ秒精度(デフォルト DAY(2) TO SECOND(6))
CREATE TABLE task_logs (
task_id NUMBER PRIMARY KEY,
task_name VARCHAR2(100),
start_ts TIMESTAMP,
finish_ts TIMESTAMP,
elapsed_time INTERVAL DAY(3) TO SECOND(3) -- 最大 999日・ミリ秒精度
);
-- TIMESTAMP 同士の引き算は INTERVAL DAY TO SECOND になる
INSERT INTO task_logs (task_id, task_name, start_ts, finish_ts, elapsed_time)
VALUES (
1, 'nightly_batch',
TIMESTAMP '2024-04-09 02:00:00',
TIMESTAMP '2024-04-09 03:45:30',
TIMESTAMP '2024-04-09 03:45:30' - TIMESTAMP '2024-04-09 02:00:00'
-- → INTERVAL '0 01:45:30.000000' DAY TO SECOND
);
-- NUMTODSINTERVAL で数値を変換する
SELECT NUMTODSINTERVAL(90, 'MINUTE') FROM DUAL; -- 90分 → INTERVAL '0 01:30:00'
SELECT NUMTODSINTERVAL(3600, 'SECOND') FROM DUAL; -- 3600秒 → INTERVAL '0 01:00:00'
SELECT NUMTODSINTERVAL(1.5, 'DAY') FROM DUAL; -- 1.5日 → INTERVAL '1 12:00:00'
INTERVAL 同士の演算と EXTRACT
INTERVAL 同士の加算・減算・スカラー倍・EXTRACT
-- INTERVAL 同士の加算・減算
SELECT INTERVAL '1' HOUR + INTERVAL '30' MINUTE FROM DUAL; -- 1時間30分
SELECT INTERVAL '2' DAY - INTERVAL '12' HOUR FROM DUAL; -- 1日12時間
-- 注意: YEAR TO MONTH と DAY TO SECOND は直接加算できない(型が異なる)
-- スカラー倍: INTERVAL * 数値
SELECT INTERVAL '1' HOUR * 8 FROM DUAL; -- 8時間
SELECT INTERVAL '30' DAY / 2 FROM DUAL; -- 15日
-- EXTRACT で INTERVAL から特定の要素を取り出す
SELECT EXTRACT(HOUR FROM INTERVAL '3 10:30:45' DAY TO SECOND) FROM DUAL; -- 10
SELECT EXTRACT(MINUTE FROM INTERVAL '3 10:30:45' DAY TO SECOND) FROM DUAL; -- 30
SELECT EXTRACT(SECOND FROM INTERVAL '3 10:30:45' DAY TO SECOND) FROM DUAL; -- 45
SELECT EXTRACT(DAY FROM INTERVAL '3 10:30:45' DAY TO SECOND) FROM DUAL; -- 3
-- 注意: EXTRACT(DAY FROM INTERVAL '3 10:30:45') = 3(時・分・秒は別に EXTRACT する)
SELECT EXTRACT(YEAR FROM INTERVAL '2-6' YEAR TO MONTH) FROM DUAL; -- 2
SELECT EXTRACT(MONTH FROM INTERVAL '2-6' YEAR TO MONTH) FROM DUAL; -- 6
-- INTERVAL を秒数に変換する(DAY TO SECOND の場合)
SELECT
elapsed_time,
EXTRACT(DAY FROM elapsed_time) * 86400 +
EXTRACT(HOUR FROM elapsed_time) * 3600 +
EXTRACT(MINUTE FROM elapsed_time) * 60 +
EXTRACT(SECOND FROM elapsed_time) AS total_seconds
FROM task_logs;
-- INTERVAL を数値(秒数)に変換したい場合はこの方法を使う
-- (直接 TO_NUMBER(elapsed_time) はできない)
実務ユースケース
SLA 管理・遅延計算・期限チェック
-- SLA: 注文から出荷まで 24時間以内かどうかを確認する
SELECT
order_id,
ordered_at,
shipped_at,
shipped_at - ordered_at AS actual_time,
INTERVAL '24' HOUR AS sla_limit,
CASE WHEN shipped_at - ordered_at > INTERVAL '24' HOUR
THEN '遅延'
ELSE 'OK'
END AS sla_status
FROM shipments
WHERE shipped_at IS NOT NULL;
-- 有効期限チェック: 契約終了まで 30日以内のレコードを抽出する
SELECT
contract_id,
contract_name,
start_date,
start_date + duration AS end_date,
(start_date + duration) - SYSDATE AS days_remaining
FROM contracts
WHERE (start_date + duration) - SYSDATE <= INTERVAL '30' DAY
AND (start_date + duration) >= SYSDATE;
-- 業務時間内の経過時間計算(平日9時〜18時の合計稼働時間)
-- INTERVAL を合計する集計: SUM は INTERVAL に使えないため、秒数に変換して集計する
SELECT
task_name,
SUM(
EXTRACT(DAY FROM elapsed_time) * 86400 +
EXTRACT(HOUR FROM elapsed_time) * 3600 +
EXTRACT(MINUTE FROM elapsed_time) * 60 +
EXTRACT(SECOND FROM elapsed_time)
) / 3600 AS total_hours -- 合計秒数 → 時間に変換
FROM task_logs
GROUP BY task_name;
-- SUM(INTERVAL) は直接使えない → 秒数に変換してから集計する
まとめ
- INTERVAL YEAR TO MONTH:年と月の期間を表す。INTERVAL ‘Y-M’ YEAR TO MONTH の形式で書く。契約期間・勤続年数などに使う
- INTERVAL DAY TO SECOND:日・時・分・秒(最大マイクロ秒)の期間を表す。INTERVAL ‘D HH:MM:SS’ DAY TO SECOND の形式。TIMESTAMP の差は自動的にこの型になる
- 精度指定:YEAR(n) / DAY(n) で先頭フィールドの最大桁数、SECOND(s) で小数秒の桁数を指定できる
- 変換関数:NUMTOYMINTERVAL(n, ‘YEAR’|’MONTH’) と NUMTODSINTERVAL(n, ‘DAY’|’HOUR’|’MINUTE’|’SECOND’) で数値から変換できる
- EXTRACT:INTERVAL から特定の要素(DAY・HOUR・MINUTE・SECOND / YEAR・MONTH)を数値で取り出せる
- SUM 不可:INTERVAL は GROUP BY と SUM() が使えない。合計する場合は秒数に変換してから集計する
DATE・TIMESTAMP 型全般の操作については Oracle データ型完全ガイドを参照してください。NLS_DATE_FORMAT・TO_CHAR の書式コードなど日付の表示形式については Oracle NLS 設定完全ガイドも参照してください。