はじめに
Oracle AI Database 26ai(バージョン 23.26.1 以降)では、日付演算を扱う Calendar 関数が新たに導入されました。従来から TRUNC、ADD_MONTHS、TO_CHAR、EXTRACT などの関数を組み合わせることで日付演算は可能でしたが、コードが煩雑になりやすく、関数ごとに挙動が微妙に異なる点が課題でした。
新しい Calendar 関数群は、こうした日付演算をシンプルかつ一貫した形で記述できるように設計されています。年・四半期・月・週・日といった時間階層ごとに対称的な関数セットが用意されており、直感的に利用できます。また、NLS(National Language Support)設定に連動しているため、多言語対応のシステムでも扱いやすいという特徴があります。
Calendar 関数は大きく 4 種類のカテゴリに分類されます。
| カテゴリ | 代表的な関数 | 戻り値の型 | 概要 |
|---|---|---|---|
| Calendar Format String |
CALENDAR_YEAR, CALENDAR_QUARTER, CALENDAR_MONTH, CALENDAR_WEEK, CALENDAR_DAY
|
VARCHAR2 | 日付から各期間の文字列表現を返す |
| Calendar Add Periods |
CALENDAR_ADD_YEARS, CALENDAR_ADD_QUARTERS, CALENDAR_ADD_MONTHS, CALENDAR_ADD_WEEKS, CALENDAR_ADD_DAYS
|
DATE | 指定した期間数を加算した日付を返す(負値で過去も可) |
| Calendar Start/End Date |
CALENDAR_YEAR_START_DATE, CALENDAR_YEAR_END_DATE(四半期・月・週も同様) |
DATE | 各期間の開始日・終了日を返す |
| Calendar Number |
CALENDAR_YEAR_NUMBER, CALENDAR_QUARTER_OF_YEAR, CALENDAR_MONTH_OF_YEAR(他多数) |
NUMBER | 日付から各期間の数値を返す |
Calendar 関数を組み合わせると、データウェアハウスで活用できるカレンダーディメンションテーブルを簡潔に作成できます。
なお、Calendar関数と同じ構成で Fiscal および Retail 向けの関数セットも用意されています(本記事では Gregorian カレンダーの関数のみ検証します)。
-
CALENDAR_*関数(Gregorian カレンダー)の 4 カテゴリ - NLS 言語設定による出力変化の確認
- カレンダーディメンションテーブルの作成
事前準備
- Oracle AI Database 26ai(バージョン 23.26.1 以降)
- Calendar 関数はすべての Oracle 26ai ユーザーが特別な権限なしに利用可能です
手順
Step 1: Calendar Start/End Date 関数
「今年の最初の日と最後の日を取得する」というシンプルなケースで、従来の方法と新しい方法を比較します。
従来の方法:
SELECT trunc(sysdate,'YYYY') AS first_day_of_year,
add_months(trunc(sysdate,'YYYY'),12)-1 AS last_day_of_year;
Calendar 関数を使った方法:
SELECT calendar_year_start_date(sysdate) AS first_day_of_year,
calendar_year_end_date(sysdate) AS last_day_of_year;
実行結果(2026年5月4日時点):
| FIRST_DAY_OF_YEAR | LAST_DAY_OF_YEAR |
|---|---|
| 26-01-01 | 26-12-31 |
CALENDAR_YEAR_START_DATE / CALENDAR_YEAR_END_DATE はいずれも DATE 型を引数に取り、DATE 型を返します。四半期・月・週にも同等の関数が用意されています。
SELECT calendar_year_start_date(date'2026-04-04') AS year_start,
calendar_year_end_date(date'2026-04-04') AS year_end,
calendar_quarter_start_date(date'2026-04-04') AS quarter_start,
calendar_quarter_end_date(date'2026-04-04') AS quarter_end,
calendar_month_start_date(date'2026-04-04') AS month_start,
calendar_month_end_date(date'2026-04-04') AS month_end,
calendar_week_start_date(date'2026-04-04') AS week_start,
calendar_week_end_date(date'2026-04-04') AS week_end;
実行結果:
YEAR_STA YEAR_END QUARTER_ QUARTER_ MONTH_ST MONTH_EN WEEK_STA WEEK_END
-------- -------- -------- -------- -------- -------- -------- --------
26-01-01 26-12-31 26-04-01 26-06-30 26-04-01 26-04-30 26-04-02 26-04-08
Step 2: Calendar Format String 関数
CALENDAR_YEAR、CALENDAR_QUARTER、CALENDAR_MONTH、CALENDAR_WEEK、CALENDAR_DAY は日付を人間が読みやすい文字列に変換します。
SELECT calendar_year(date'2026-10-10') AS cal_year,
calendar_quarter(date'2026-10-10') AS cal_quarter,
calendar_month(date'2026-10-10') AS cal_month,
calendar_week(date'2026-10-10') AS cal_week,
calendar_day(date'2026-10-10') AS cal_day;
実行結果(セッションの言語が日本語の場合):
CAL_ CAL_QUA CAL_MONTH CAL_WEEK CAL_DAY
---- ------- ---------- -------- -------------
2026 Q4-2026 10月-2026 W41-2026 10-10月-2026
NLS 言語の変更による出力の違い
これらの関数は NLS 設定に連動しています。セッションの言語を変更すると、月名や曜日名が自動的に翻訳されます。
英語に変更する場合:
ALTER SESSION SET nls_language = 'AMERICAN';
SELECT calendar_year(date'2026-10-10') AS cal_year,
calendar_quarter(date'2026-10-10') AS cal_quarter,
calendar_month(date'2026-10-10') AS cal_month,
calendar_week(date'2026-10-10') AS cal_week,
calendar_day(date'2026-10-10') AS cal_day;
実行結果(英語):
CAL_ CAL_QUA CAL_MONT CAL_WEEK CAL_DAY
---- ------- -------- -------- -----------
2026 Q4-2026 OCT-2026 W41-2026 10-OCT-2026
Step 3: Calendar Add Periods 関数
CALENDAR_ADD_YEARS、CALENDAR_ADD_QUARTERS、CALENDAR_ADD_MONTHS、CALENDAR_ADD_WEEKS、CALENDAR_ADD_DAYS を使うと、特定の期間を加減算した日付を返せます。負の値を指定すると過去の日付を取得できます。
SELECT calendar_add_years(sysdate, 1) AS today_in_one_year,
calendar_add_years(sysdate, 2) AS today_in_two_years,
calendar_add_days (sysdate, 1) AS tomorrow,
calendar_add_days (sysdate, -1) AS yesterday;
実行結果(2026年5月4日時点):
TODAY_IN TODAY_IN TOMORROW YESTERDA
-------- -------- -------- --------
27-05-04 28-05-04 26-05-05 26-05-03
従来の ADD_MONTHS は月・年の加算に対応していましたが、週・日の加算には別途計算が必要でした。Calendar 関数では時間階層ごとに専用の関数が提供されているため、コードの意図が明確になります。
Step 4: Calendar Number 関数
日付から数値を取得する方法も、従来の方法と比較してシンプルになりました。
従来の方法(TO_CHAR を使う場合):
SELECT to_number(to_char(sysdate, 'DD')) AS day_number,
to_number(to_char(sysdate, 'MM')) AS month_number,
to_number(to_char(sysdate, 'YYYY')) AS year_number;
従来の方法(EXTRACT を使う場合):
SELECT extract(day from sysdate) AS day_number,
extract(month from sysdate) AS month_number,
extract(year from sysdate) AS year_number;
新しい Calendar 関数を使った方法:
SELECT calendar_day_of_month(sysdate) AS day_number,
calendar_month_of_year(sysdate) AS month_number,
calendar_year_number(sysdate) AS year_number;
実行結果(2026年5月4日時点):
DAY_NUMBER MONTH_NUMBER YEAR_NUMBER
---------- ------------ -----------
4 5 2026
Calendar Number 関数には以下の 9 種類が用意されています。
| 関数名 | 説明 |
|---|---|
CALENDAR_YEAR_NUMBER |
年を数値で返す |
CALENDAR_QUARTER_OF_YEAR |
年内の四半期番号(1〜4)を返す |
CALENDAR_MONTH_OF_YEAR |
年内の月番号(1〜12)を返す |
CALENDAR_MONTH_OF_QUARTER |
四半期内の月番号(1〜3)を返す |
CALENDAR_WEEK_OF_YEAR |
年内の週番号を返す |
CALENDAR_DAY_OF_YEAR |
年内の日番号(1〜365/366)を返す |
CALENDAR_DAY_OF_QUARTER |
四半期内の日番号を返す |
CALENDAR_DAY_OF_MONTH |
月内の日番号(1〜31)を返す |
CALENDAR_DAY_OF_WEEK |
週内の曜日番号を返す |
Step 5: カレンダーディメンションテーブルを作成
Calendar 関数を組み合わせると、データウェアハウスで必要なカレンダーディメンションテーブルを簡潔に構築できます。以下の例では、現在日時を基準に前後 2 年分のデータを生成します。
CREATE TABLE IF NOT EXISTS dim_calendar AS
WITH date_interval AS (
SELECT calendar_year_start_date
(calendar_add_years(sysdate, -2)) AS start_date,
calendar_year_end_date
(calendar_add_years(sysdate, 2)) AS end_date
),
date_generator AS (
SELECT calendar_add_days(start_date, rownum-1) AS d
FROM date_interval
CONNECT BY rownum-1 <= end_date - start_date
)
SELECT d AS dim_calendar_key,
d AS cal_date,
calendar_day(d) AS cal_day,
calendar_week(d) AS cal_week,
calendar_week_start_date(d) AS cal_week_start_date,
calendar_week_end_date(d) AS cal_week_end_date,
calendar_month(d) AS cal_month,
calendar_month_start_date(d) AS cal_month_start_date,
calendar_month_end_date(d) AS cal_month_end_date,
calendar_quarter(d) AS cal_quarter,
calendar_quarter_start_date(d) AS cal_quarter_start_date,
calendar_quarter_end_date(d) AS cal_quarter_end_date,
calendar_year(d) AS cal_year,
calendar_year_start_date(d) AS cal_year_start_date,
calendar_year_end_date(d) AS cal_year_end_date
FROM date_generator;
注意:
CONNECT BY rownum-1 <= end_date - start_dateのend_date - start_dateは DATE 型同士の減算で日数差を返します。生成される行数は 5 年分で約 1,826 行です。
作成されたテーブルの内容を確認します:
SELECT * FROM dim_calendar
WHERE cal_month = calendar_month(sysdate) and rownum < 4
ORDER BY cal_date;
DIM_CALE CAL_DATE CAL_DAY CAL_WEEK CAL_WEEK CAL_WEEK
-------- -------- --------------------- --------- -------- --------
CAL_MONTH CAL_MONT CAL_MONT CAL_QUAR CAL_QUAR CAL_QUAR CAL_Y CAL_YEAR
------------------ -------- -------- -------- -------- -------- ----- --------
CAL_YEAR
--------
26-05-01 26-05-01 01-MAY-2026 W18-2026 26-04-30 26-05-06
MAY-2026 26-05-01 26-05-31 Q2-2026 26-04-01 26-06-30 2026 26-01-01
26-12-31
26-05-02 26-05-02 02-MAY-2026 W18-2026 26-04-30 26-05-06
MAY-2026 26-05-01 26-05-31 Q2-2026 26-04-01 26-06-30 2026 26-01-01
26-12-31
26-05-03 26-05-03 03-MAY-2026 W18-2026 26-04-30 26-05-06
MAY-2026 26-05-01 26-05-31 Q2-2026 26-04-01 26-06-30 2026 26-01-01
26-12-31
クリーンアップ
検証が完了したらテーブルを削除します。
DROP TABLE IF EXISTS dim_calendar;
おわりに
今回の検証で確認できたポイントをまとめます。
-
可読性の向上: 従来の
TRUNC、ADD_MONTHS、TO_CHARなどの組み合わせに比べ、Calendar 関数は意図が明確で読みやすいコードになります。 - 一貫性のある API 設計: 年・四半期・月・週・日という時間階層ごとに対称的な関数セットが提供されており、覚えやすく使いやすい設計になっています。
-
NLS 対応:
CALENDAR_YEAR、CALENDAR_MONTHなどの文字列関数はセッションの NLS 設定に連動し、多言語対応のシステムでも自然に動作します。 - データウェアハウス用途に最適: カレンダーディメンションテーブルの作成など、時間軸を必要とするデータ分析基盤の構築がよりシンプルに記述できます。
Gregorian カレンダー以外にも Fiscal・Retail カレンダー向けの関数セットが用意されているため、会計・小売業などのドメインでも幅広く活用できます。