Oracle 12c で導入された不可視列(Invisible Column)は、SELECT * や DESCRIBE コマンドの出力に表示されない列です。列名を明示的に指定した SELECT 列名 FROM ... では通常通り参照できます。
既存のアプリケーションが SELECT * を使っている場合、新しい列を追加するとアプリケーション側で列数が変わり不具合が生じることがあります。不可視列を使えば、既存アプリケーションに影響を与えずに新しい列をテーブルに追加できます。段階的なスキーマ移行・追加列の準備に役立ちます。
この記事でわかること
- 不可視列の仕組みと SELECT * / DESCRIBE での動作
- CREATE TABLE で INVISIBLE 列を定義する方法
- ALTER TABLE MODIFY で既存列を INVISIBLE / VISIBLE に変更する方法
- INSERT 文での不可視列の扱い(列リストなし INSERT の挙動)
- 不可視列への明示的なアクセス方法
- USER_TAB_COLUMNS.HIDDEN_COLUMN で不可視列を確認する方法
- 段階的スキーマ移行での活用パターン
不可視列と SELECT * / DESCRIBE の動作
不可視列を含むテーブルの SELECT * の動作
-- 不可視列(INVISIBLE)を含むテーブルを作成する
CREATE TABLE employees_new (
employee_id NUMBER PRIMARY KEY,
first_name VARCHAR2(50),
last_name VARCHAR2(50),
email VARCHAR2(100),
salary NUMBER,
department_id NUMBER,
-- 不可視列: 既存アプリケーションに影響なく列を追加する
created_by VARCHAR2(30) INVISIBLE DEFAULT USER,
created_at TIMESTAMP INVISIBLE DEFAULT SYSTIMESTAMP,
row_version NUMBER INVISIBLE DEFAULT 1
);
-- SELECT * では不可視列は返されない
SELECT * FROM employees_new;
-- → employee_id, first_name, last_name, email, salary, department_id のみ返される
-- → created_by, created_at, row_version は含まれない
-- DESCRIBE でも不可視列は表示されない
DESC employees_new;
-- → 可視列のみ表示される(不可視列は一覧に出ない)
-- 不可視列を明示的に指定すれば取得できる
SELECT employee_id, first_name, created_by, created_at
FROM employees_new
WHERE employee_id = 100;
-- → 明示的に指定した created_by, created_at は正常に取得できる
-- 不可視列を含む全列を取得するには列名を明示する
SELECT employee_id, first_name, last_name, email, salary,
department_id, created_by, created_at, row_version
FROM employees_new
WHERE employee_id = 100;
ALTER TABLE で列の可視・不可視を変更する
ALTER TABLE MODIFY / ADD で列を不可視にする・戻す
-- 既存テーブルに不可視列を追加する
ALTER TABLE employees
ADD bonus_amount NUMBER INVISIBLE;
-- 既存の可視列を不可視に変更する
ALTER TABLE employees
MODIFY salary INVISIBLE;
-- 注意: salary は INVISIBLE になるので SELECT * には表示されなくなる
-- 不可視列を可視に戻す
ALTER TABLE employees
MODIFY salary VISIBLE;
-- 複数列をまとめて変更する
ALTER TABLE employees
MODIFY (
bonus_amount VISIBLE,
created_by VISIBLE,
row_version INVISIBLE
);
-- 不可視列の状態を確認する
SELECT
column_name,
column_id,
data_type,
nullable,
hidden_column, -- YES: 不可視 / NO: 可視
virtual_column -- YES: 仮想列
FROM USER_TAB_COLUMNS
WHERE table_name = 'EMPLOYEES'
ORDER BY column_id NULLS LAST;
-- 不可視列は column_id が NULL になる(列順序がないため)
INSERT 文での不可視列の扱い
INSERT VALUES での重要な注意点
列リストなしの
列リストなしの
INSERT INTO table VALUES (...) では、不可視列は自動的にスキップされます(デフォルト値または NULL が挿入される)。既存のアプリケーションがこの形式の INSERT を使っていても、列数エラーは発生しません。
不可視列を含むテーブルへの INSERT
-- 列リストなし INSERT: 不可視列はスキップされる
-- → visible な列だけに値を指定する形式で動作する
INSERT INTO employees_new VALUES (
100, 'John', 'Doe', 'john@example.com', 50000, 10
);
-- created_by, created_at, row_version(INVISIBLE列)はデフォルト値が使われる
-- エラーにはならない(列数が可視列数と一致していればOK)
-- 不可視列に明示的に値を挿入するには列リストを指定する
INSERT INTO employees_new (
employee_id, first_name, last_name, email, salary, department_id,
created_by, created_at, row_version -- 不可視列も列リストに含める
) VALUES (
101, 'Jane', 'Smith', 'jane@example.com', 60000, 20,
'ADMIN', SYSTIMESTAMP, 1
);
-- SELECT * FROM table INSERT:
-- ソーステーブルに不可視列がある場合、SELECT * ではそれが除外される
-- INSERT INTO target SELECT * FROM employees_new;
-- → employees_new の不可視列は SELECT * に含まれないため target には反映されない
段階的スキーマ移行での活用パターン
本番環境で稼働中のアプリケーションのテーブルに新列を追加する場合、SELECT * を使っているコードが壊れる可能性があります。不可視列を使うと、まず不可視で列を追加してデータを準備し、アプリケーション側の準備が整った段階で可視に切り替えられます。
不可視列を使った段階的スキーマ移行の手順
-- ステップ 1: 不可視列として新列を追加する(既存アプリへの影響なし)
ALTER TABLE orders ADD (
region_code VARCHAR2(10) INVISIBLE,
priority NUMBER(1) INVISIBLE DEFAULT 3
);
-- ステップ 2: 不可視列にデータを投入する(バッチ更新)
UPDATE orders
SET region_code =
CASE
WHEN customer_id BETWEEN 1 AND 10000 THEN 'EAST'
WHEN customer_id BETWEEN 10001 AND 20000 THEN 'WEST'
ELSE 'OTHER'
END,
priority = CASE
WHEN amount >= 100000 THEN 1
WHEN amount >= 50000 THEN 2
ELSE 3
END;
COMMIT;
-- ステップ 3: データが正しいことを確認する
SELECT order_id, amount, region_code, priority
FROM orders
WHERE region_code IS NULL;
-- → NULL が残っている行を確認・修正する
-- ステップ 4: アプリケーション側の準備が整ったら VISIBLE に切り替える
ALTER TABLE orders MODIFY (
region_code VISIBLE,
priority VISIBLE
);
-- これ以降 SELECT * で新列が見えるようになる
不可視列の制限事項と注意点
不可視列の制限事項
- 主キーには使えない:主キー列は可視でなければならない
- IOT(索引構成表)の主キー列:索引構成表のキー列は INVISIBLE にできない
- 列順序が NULL:不可視列は USER_TAB_COLUMNS.COLUMN_ID が NULL になる(可視列の後に格納される)
- 外部テーブルには使えない:外部テーブルの列は INVISIBLE にできない
- Oracle 12c 以降限定:Oracle 11g 以前では使えない
不可視列の状態を詳細に確認する
-- USER_TAB_COLUMNS で不可視列の一覧を確認する
SELECT
table_name,
column_name,
column_id, -- NULL: 不可視列(可視列の後ろに格納)
data_type,
data_length,
nullable,
data_default, -- デフォルト値
hidden_column, -- YES: 不可視 / NO: 可視
virtual_column -- YES: 仮想列(INVISIBLE と独立した属性)
FROM USER_TAB_COLUMNS
WHERE hidden_column = 'YES'
ORDER BY table_name, column_name;
-- 不可視列にインデックスは作成できる(ただしインデックス自体は visible になる)
CREATE INDEX orders_region_idx ON orders(region_code);
-- region_code が INVISIBLE でもインデックスは通常通り機能する
-- 不可視列に NOT NULL 制約を追加する場合は DEFAULT を指定する(既存行対策)
ALTER TABLE orders ADD
audit_flag VARCHAR2(1) INVISIBLE DEFAULT 'N' NOT NULL;
-- DEFAULT がなければ既存行で NOT NULL 違反になるため必ず指定する
まとめ
- 不可視列(INVISIBLE):Oracle 12c 以降の機能。SELECT * や DESCRIBE に表示されない列。明示的に列名を指定すれば通常通りアクセスできる
- INSERT での動作:列リストなし INSERT では不可視列はスキップされ、デフォルト値または NULL が使われる。既存アプリへの影響を避けられる
- ALTER TABLE MODIFY:既存列を INVISIBLE / VISIBLE に切り替えられる。主キー列には不可視を設定できない
- HIDDEN_COLUMN = ‘YES’:USER_TAB_COLUMNS.HIDDEN_COLUMN で不可視列を識別できる。不可視列は COLUMN_ID が NULL になる
- 段階的スキーマ移行:不可視で列を追加→データを準備→アプリケーション対応→VISIBLE に切り替え、というステップで安全に移行できる
仮想列(Virtual Column)と組み合わせて派生列を管理する方法は Oracle 仮想列完全ガイドを参照してください。非表示インデックス(Invisible Index)でインデックスの効果をテストする方法は 非表示インデックス完全ガイドも参照してください。