Oracle INTERVAL 數據類型專門用於存儲「兩個時間點之間的間隔」,區別于 DATE/TIMESTAMP 表示「絕對時間點」。INTERVAL 分為兩大家族:INTERVAL YEAR TO MONTH (年月間隔) 與 INTERVAL DAY TO SECOND (天秒間隔),各自擁有精度控制機制,是處理周期性業務、SLA 計算、分區維護的利器。
INTERVAL YEAR [(year_precision)] TO MONTH
-- year_precision: 年份位數,範圍 0-9,默認 2 (即最大 99 年)
INTERVAL '100' YEAR(3) -- 100 年,需精度 3
INTERVAL '123-2' YEAR(4) TO MONTH -- 123 年 2 月
INTERVAL '100' MONTH -- 100 個月
INTERVAL DAY [(day_precision)] TO SECOND [(fractional_seconds_precision)]
-- day_precision: 天數位數,0-9,默認 2
-- fractional_seconds_precision: 秒小數位數,0-9,默認 6 (微秒級)
| 格式示例 | 含義 | 關鍵範圍 |
|---|---|---|
INTERVAL '30.12345' SECOND(2,4) | 30.1235 秒 (四捨五入到 4 位小數) | SECOND: 0-59.999999999 |
INTERVAL '1 2:3:4' DAY TO SECOND | 1 天 2 時 3 分 4 秒 | HOUR: 0-23, MINUTE: 0-59 |
INTERVAL '400 5' DAY(3) TO HOUR | 400 天 5 小時 (天精度 3 位) | DAY: 0-999999999 |
INTERVAL '1:2:3' HOUR TO SECOND | 1 時 2 分 3 秒 |
SELECT DATE '2010-01-01' + INTERVAL '21' YEAR FROM DUAL; -- 2031-01-01
SELECT DATE '2010-01-01' + INTERVAL '123-2' YEAR(4) TO MONTH FROM DUAL; -- 2133-03-01
SELECT DATE '2010-01-01' + INTERVAL '100' MONTH FROM DUAL; -- 2018-05-01
SELECT DATE '2010-01-01' + INTERVAL '100' DAY(2) FROM DUAL; -- 2010-04-11
SELECT DATE '2010-01-01' + INTERVAL '1 2' DAY TO HOUR FROM DUAL; -- 1天2小時後
SELECT DATE '2010-01-01' + INTERVAL '1 2:3' DAY TO MINUTE FROM DUAL; -- 1天2時3分後
SELECT DATE '2010-01-01' + INTERVAL '1 2:3:4' DAY TO SECOND FROM DUAL; -- 1天2時3分4秒後
SELECT DATE '2010-01-01' + INTERVAL '1' HOUR FROM DUAL; -- 1小時後
SELECT DATE '2010-01-01' + INTERVAL '1:2' HOUR TO MINUTE FROM DUAL; -- 1時2分後
SELECT DATE '2010-01-01' + INTERVAL '1:2:3' HOUR TO SECOND FROM DUAL; -- 1時2分3秒後
SELECT DATE '2010-01-01' + INTERVAL '1:2' MINUTE TO SECOND FROM DUAL; -- 1分2秒後
-- 工單創建時間 created_at,要求 4 小時內響應
SELECT
ticket_id,
CASE
WHEN (SYSTIMESTAMP - created_at) > INTERVAL '4' HOUR
THEN 'SLA_BREACH'
ELSE 'WITHIN_SLA'
END AS sla_status
FROM tickets
WHERE status = 'OPEN';
-- 生成未來 12 個月分區定義
SELECT
'PARTITION p' || TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE,'MM'), LEVEL-1), 'YYYYMM') ||
' VALUES LESS THAN (DATE ''' || TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE,'MM'), LEVEL), 'YYYY-MM-DD') || ''')' AS partition_ddl
FROM dual
CONNECT BY LEVEL <= 12;
-- 配合 INTERVAL 分區 (11g+): PARTITION BY RANGE (created_at) INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
INTERVAL DAY TO SECOND 默認 DAY(2),最大 99 天。存儲 100 天以上間隔必須聲明 DAY(3) 或更高,否則插入報 ORA-01873: the leading precision of the interval is too small。SECOND(3) 只保留毫秒,微秒被截斷 (非四捨五入)。高精度計時必須聲明 SECOND(6) 或 (9)。INTERVAL '100' DAY(2) 報錯,必須 DAY(3)。字面量解析時先檢查精度再賦值。INTERVAL YEAR TO MONTH 不能直接與 INTERVAL DAY TO SECOND 相加減,需轉換為統一單位 (如 NUMTODSINTERVAL/NUMTOYMINTERVAL)。| 函數 | 用途 | 示例 |
|---|---|---|
NUMTODSINTERVAL(n, 'DAY|HOUR|MINUTE|SECOND') | 數值 → DAY TO SECOND 間隔 | NUMTODSINTERVAL(3600, 'SECOND') = INTERVAL '1:0:0' HOUR TO SECOND |
NUMTOYMINTERVAL(n, 'YEAR|MONTH') | 數值 → YEAR TO MONTH 間隔 | NUMTOYMINTERVAL(18, 'MONTH') = INTERVAL '1-6' YEAR TO MONTH |
TO_DSINTERVAL('str') | 字符串 → DAY TO SECOND | TO_DSINTERVAL('1 2:3:4.567') |
TO_YMINTERVAL('str') | 字符串 → YEAR TO MONTH | TO_YMINTERVAL('1-2') |
EXTRACT(DAY|HOUR|MINUTE|SECOND FROM interval) | 提取間隔組件 | EXTRACT(HOUR FROM INTERVAL '1 2:3:4' DAY TO SECOND) = 2 |
掌握 INTERVAL 精度聲明與字面量格式,讓你在處理「相對時間」業務時,擁有如同處理「絕對時間」般精確、可讀、可維護的代碼表達力。