Oracle のデータ型を正しく選ぶことは、ストレージ効率・検索性能・型変換エラーの防止につながります。特に NUMBER の精度指定・VARCHAR2 と CHAR の違い・DATE と TIMESTAMP の差・CLOB と VARCHAR2 の選択基準は、設計時に迷いやすいポイントです。この記事でそれぞれの特性と使い分けを整理します。
この記事でわかること
- NUMBER(p,s) の精度・スケールの意味と設定方法
- VARCHAR2 と CHAR の違い・NVARCHAR2・CLOB の使い分け
- DATE と TIMESTAMP の違い・TIMESTAMP WITH TIME ZONE
- INTERVAL 型で期間(月数・秒数)を格納・演算する方法
- CLOB・BLOB・BFILE の違いと選択基準
- Oracle 21c の JSON 型・23ai の BOOLEAN 型
- 型変換関数(TO_NUMBER・TO_CHAR・TO_DATE・CAST)のまとめ
数値型:NUMBER・FLOAT・BINARY_FLOAT
| データ型 | 説明 | 推奨用途 |
|---|---|---|
NUMBER(p,s) |
10進数。p=精度(全桁数)、s=スケール(小数点以下の桁数) | 金額・数量など正確な数値。Oracle のデフォルト数値型 |
NUMBER |
精度・スケール未指定。最大38桁 | 汎用だが精度管理が必要な場合は p,s を指定 |
INTEGER |
NUMBER(38,0) の別名 | 整数値(行IDなど) |
FLOAT(b) |
2進浮動小数点。b=ビット精度(最大126) | 科学計算(正確な10進数が不要な場合) |
BINARY_FLOAT |
32ビット IEEE 754 浮動小数点 | 高速な浮動小数点演算が必要な場合(OLAP等) |
BINARY_DOUBLE |
64ビット IEEE 754 浮動小数点 | BINARY_FLOAT より精度が必要な場合 |
NUMBER(p,s) の精度とスケールの使い方
-- NUMBER(p, s):
-- p = 有効桁数(全体の桁数)
-- s = スケール(小数点以下の桁数)
-- 例:
-- NUMBER(5,2) → 最大 999.99(整数部3桁・小数部2桁)
-- NUMBER(10,0) → 最大 9999999999(整数10桁)
-- NUMBER(6,-2) → スケール負数: 最大 9999900(100の位で丸める)
CREATE TABLE products (
product_id NUMBER(10) PRIMARY KEY, -- 整数
unit_price NUMBER(10, 2) NOT NULL, -- 金額(小数2桁)
weight_kg NUMBER(6, 3), -- 重量(3桁小数)
tax_rate NUMBER(5, 4) -- 税率(0.1000 など)
);
-- 格納される値と精度の例
-- NUMBER(5,2) に 1234.5 → エラー(整数部が3桁を超える)
-- NUMBER(5,2) に 123.456 → 123.46 に丸められる
-- NUMBER(5,2) に 123.454 → 123.45 に丸められる
-- BINARY_FLOAT / BINARY_DOUBLE は近似値になることに注意
SELECT 0.1 + 0.2 FROM DUAL; -- NUMBER: 0.3 (正確)
SELECT (0.1 + 0.2) - 0.3 FROM DUAL; -- NUMBER: 0 (正確)
-- BINARY_FLOAT では 0.300000012 のような近似値になる可能性がある
文字列型:VARCHAR2・CHAR・NVARCHAR2・CLOB
| データ型 | 最大長 | 説明 | 推奨用途 |
|---|---|---|---|
VARCHAR2(n) |
列: 4000B / 32767B* | 可変長文字列。実際の長さ分だけ格納 | 一般的なテキスト(名前・住所など) |
CHAR(n) |
2000B | 固定長文字列。n未満は空白埋め | 固定長コード(都道府県コード・フラグ等) |
NVARCHAR2(n) |
4000B / 32767B* | Unicode 可変長(文字数単位) | 多言語対応が必要な場合(Oracle 12c 以降は VARCHAR2 も UTF-8可) |
NCHAR(n) |
2000B | Unicode 固定長(文字数単位) | Unicode 固定長コード |
CLOB |
128TB | 文字型大オブジェクト | 長い HTML・XML・JSON・テキストなど |
NCLOB |
128TB | Unicode CLOB | 多言語対応の大テキスト |
* 32767B は MAX_STRING_SIZE=EXTENDED(12c 以降)有効時
VARCHAR2 と CHAR の違い・比較の注意点
-- CHAR(5) は常に5バイトに空白埋めして格納される
-- → 'AB' を格納すると内部的には 'AB '(空白3個)になる
CREATE TABLE test_types (
c1 CHAR(5),
c2 VARCHAR2(5)
);
INSERT INTO test_types VALUES ('AB', 'AB');
-- CHAR は末尾空白を無視して比較するため = では一致するが LENGTH は異なる
SELECT LENGTH(c1), LENGTH(c2) FROM test_types;
-- CHAR: 5, VARCHAR2: 2
-- CHAR 列を WHERE = で比較する場合、空白は無視されるが
-- || で連結すると 'AB Suffix' のように空白が含まれる
SELECT c1 || 'Suffix' FROM test_types; -- 'AB Suffix'(CHAR の空白が残る)
SELECT c2 || 'Suffix' FROM test_types; -- 'ABSuffix'(VARCHAR2 は空白なし)
-- 実務: CHAR は固定長コードのみに使用。それ以外は VARCHAR2 を使う
VARCHAR2 vs CLOB:4000バイトの壁
標準設定の Oracle では VARCHAR2 の最大長は 4000 バイト(Byte セマンティクス)です。4000 バイトを超えるテキストには
標準設定の Oracle では VARCHAR2 の最大長は 4000 バイト(Byte セマンティクス)です。4000 バイトを超えるテキストには
CLOB を使います。ただし CLOB は LIKE 検索の制限・インデックスの制限があるため、検索が必要なテキストは VARCHAR2 で設計することを優先してください。Oracle 12c 以降に MAX_STRING_SIZE=EXTENDED を設定すれば VARCHAR2 が最大 32767 バイトになります。
日付型:DATE・TIMESTAMP・INTERVAL
| データ型 | 精度 | 説明 |
|---|---|---|
DATE |
秒 | 年月日・時分秒を格納。ミリ秒は持たない |
TIMESTAMP(f) |
サブ秒 | DATE + 小数秒(f=桁数、0〜9。デフォルト6) |
TIMESTAMP WITH TIME ZONE |
サブ秒+TZ | タイムゾーン情報込みで格納 |
TIMESTAMP WITH LOCAL TIME ZONE |
サブ秒+TZ | DB のタイムゾーンに変換して格納・取得時にセッションTZに変換 |
INTERVAL YEAR TO MONTH |
年・月 | 月単位の期間を格納 |
INTERVAL DAY TO SECOND |
日〜秒 | 日・時・分・秒単位の期間を格納 |
DATE と TIMESTAMP の違い・ミリ秒の扱い
-- DATE: 秒単位まで。ミリ秒は切り捨て
-- TIMESTAMP: 小数秒(デフォルト6桁=マイクロ秒)まで格納
CREATE TABLE events (
event_id NUMBER PRIMARY KEY,
event_date DATE, -- 秒単位
event_ts TIMESTAMP(3), -- ミリ秒単位(f=3)
event_ts_tz TIMESTAMP(6) WITH TIME ZONE -- タイムゾーン付き
);
-- DATE に SYSDATE(秒単位)を格納
INSERT INTO events (event_id, event_date) VALUES (1, SYSDATE);
-- TIMESTAMP に SYSTIMESTAMP(マイクロ秒)を格納
INSERT INTO events (event_id, event_ts, event_ts_tz)
VALUES (2, SYSTIMESTAMP, SYSTIMESTAMP);
-- TIMESTAMP(3) に格納すると 123.456789 → 123 にミリ秒で切り捨て
-- TO_TIMESTAMP で文字列から変換
SELECT TO_TIMESTAMP('2024-03-15 10:30:00.123456', 'YYYY-MM-DD HH24:MI:SS.FF')
FROM DUAL;
INTERVAL 型:期間を格納・演算する
-- INTERVAL YEAR TO MONTH: 年・月の期間を格納
-- INTERVAL DAY TO SECOND: 日〜秒の期間を格納
-- INTERVAL リテラル
SELECT
INTERVAL '1-6' YEAR TO MONTH AS "1年6ヶ月",
INTERVAL '5' YEAR AS "5年",
INTERVAL '3' MONTH AS "3ヶ月",
INTERVAL '2 04:30:00' DAY TO SECOND AS "2日4時間30分",
INTERVAL '45' MINUTE AS "45分"
FROM DUAL;
-- DATE との演算(数値の加算は日単位)
SELECT
SYSDATE + 30 AS "30日後",
SYSDATE + INTERVAL '3' MONTH AS "3ヶ月後", -- 月末日処理あり
SYSDATE + INTERVAL '2:30' HOUR TO MINUTE AS "2時間30分後"
FROM DUAL;
-- 2つの日付の差(INTERVAL で取得)
SELECT
(TIMESTAMP '2024-12-31 23:59:59' - TIMESTAMP '2024-01-01 00:00:00')
DAY(3) TO SECOND AS diff
FROM DUAL;
-- 結果: +365 23:59:59.000000
-- 月数差は MONTHS_BETWEEN
SELECT MONTHS_BETWEEN(DATE '2025-03-31', DATE '2024-09-30') FROM DUAL; -- 6
ラージオブジェクト型:CLOB・BLOB・BFILE
| データ型 | 最大サイズ | 格納場所 | 用途 |
|---|---|---|---|
CLOB |
128TB | DB内(行外) | 長い文字データ(HTML・XML・JSON・文書) |
NCLOB |
128TB | DB内(行外) | Unicode 文字データ |
BLOB |
128TB | DB内(行外) | バイナリデータ(画像・PDF・動画) |
BFILE |
OS 依存 | DB 外(ファイルシステム) | OS ファイルへの参照のみ(DB は参照を格納) |
CLOB・BLOB の基本操作
-- CLOB に長文テキストを格納
CREATE TABLE documents (
doc_id NUMBER PRIMARY KEY,
doc_title VARCHAR2(200),
doc_content CLOB -- 長いHTMLや本文
);
-- CLOB に INSERT(4000バイト以内ならリテラルで可)
INSERT INTO documents VALUES (
1,
'Oracle入門',
'これは長い文書の内容です。'
);
-- 4000バイト超の場合は DBMS_LOB.WRITEAPPEND か TO_CLOB() を使う
DECLARE
v_clob CLOB := EMPTY_CLOB();
v_chunk VARCHAR2(32767);
BEGIN
INSERT INTO documents VALUES (2, '大きな文書', v_clob)
RETURNING doc_content INTO v_clob;
v_chunk := RPAD('あ', 10000, 'あ'); -- 10000文字
DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_chunk), v_chunk);
COMMIT;
END;
/
-- CLOB の部分取得
SELECT DBMS_LOB.SUBSTR(doc_content, 100, 1) AS first_100
FROM documents
WHERE doc_id = 2;
-- CLOB の全文検索(LIKE は CLOB にも使えるが大きなデータでは遅い)
SELECT doc_title
FROM documents
WHERE doc_content LIKE '%Oracle%';
Oracle 21c・23ai の追加データ型
| バージョン | データ型 | 説明 |
|---|---|---|
| Oracle 21c | JSON |
ネイティブ JSON 型(OSON 形式でバイナリ格納・パース済みで高速) |
| Oracle 23ai | BOOLEAN |
真偽値型(TRUE/FALSE/NULL。従来は NUMBER(1) や CHAR(1) で代用していた) |
| Oracle 23ai | VECTOR |
AI ベクトル検索用の浮動小数点配列型(次元数指定可) |
BOOLEAN 型(Oracle 23ai)
-- Oracle 23ai 以前は NUMBER(1) や CHAR(1 CHAR) で代用していた
-- Oracle 23ai 以降は BOOLEAN 型が使用可能
CREATE TABLE feature_flags (
flag_id NUMBER PRIMARY KEY,
flag_name VARCHAR2(100),
is_enabled BOOLEAN DEFAULT FALSE NOT NULL
);
INSERT INTO feature_flags VALUES (1, 'dark_mode', TRUE);
INSERT INTO feature_flags VALUES (2, 'beta_api', FALSE);
SELECT flag_name, is_enabled
FROM feature_flags
WHERE is_enabled = TRUE;
-- IS TRUE / IS FALSE での比較も可能
SELECT flag_name FROM feature_flags WHERE is_enabled IS TRUE;
SELECT flag_name FROM feature_flags WHERE is_enabled IS NOT TRUE; -- FALSE or NULL
型変換関数まとめ
| 関数 | 変換方向 | よく使う書式 |
|---|---|---|
TO_NUMBER(str, fmt) |
文字列→NUMBER | TO_NUMBER('1,234', '9,999') |
TO_CHAR(n, fmt) |
NUMBER→文字列 | TO_CHAR(1234567, 'FM9,999,999') |
TO_DATE(str, fmt) |
文字列→DATE | TO_DATE('2024-03-15', 'YYYY-MM-DD') |
TO_CHAR(d, fmt) |
DATE→文字列 | TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') |
TO_TIMESTAMP(str, fmt) |
文字列→TIMESTAMP | TO_TIMESTAMP('2024-03-15 10:30:00.123', 'YYYY-MM-DD HH24:MI:SS.FF') |
CAST(expr AS type) |
型変換(汎用) | CAST('100' AS NUMBER) |
暗黙型変換の落とし穴
Oracle は
Oracle は
WHERE hire_date = '2024-03-15' のように文字列を DATE に暗黙変換しますが、変換は NLS_DATE_FORMAT に依存するためサーバー設定によって挙動が変わります。本番環境と開発環境で NLS_DATE_FORMAT が異なると、同じ SQL で結果が変わったりエラーになります。日付リテラルは必ず DATE '2024-03-15' または TO_DATE('2024-03-15', 'YYYY-MM-DD') で明示してください。
まとめ
- NUMBER(p,s):金額・数量は必ず精度を指定。BINARY_FLOAT は近似値になることに注意
- VARCHAR2 vs CHAR:固定長コード以外は VARCHAR2 を使う。CHAR は空白埋めで比較・連結に注意
- CLOB:4000バイト超のテキストに。LIKE 検索は遅いため設計段階で考慮
- DATE vs TIMESTAMP:ミリ秒以下が必要なら TIMESTAMP(3〜6)。ログ記録・API 連携は TIMESTAMP が安全
- INTERVAL:期間を値として格納・演算できる。数値(日数)加算より意図が明確
- BOOLEAN(23ai〜):真偽値に使える。それ以前は NUMBER(1) または CHAR(1) で代用
日付の書式変換・NLS_DATE_FORMAT の詳細はTO_CHAR / TO_DATE 日付フォーマット完全ガイドを、NLS 設定の確認・変更方法はNLS設定完全ガイドも参照してください。

