Oracle で「このカラムはどのテーブルにあるか」「テーブルに特定のカラムが存在するか」を調べるには、データディクショナリビュー ALL_TAB_COLUMNS を使います。マイグレーション前の影響調査、カラム名の命名規則チェック、テーブル設計のレビューなど、実務で頻繁に使うテクニックです。
本記事では、USER / ALL / DBA の使い分け、完全一致 / 部分一致 / 正規表現での検索、データ型・NULL 制約・デフォルト値の確認、PL/SQL での EXISTS 判定まで解説します。
この記事でわかること
・USER_TAB_COLUMNS / ALL_TAB_COLUMNS / DBA_TAB_COLUMNS の使い分け
・カラム名の完全一致・部分一致・正規表現検索
・カラムのデータ型・桁数・NULL 制約・デフォルト値の確認
・特定カラムがどのテーブルに存在するか横断検索
・PL/SQL で「カラムが存在するか」を判定する方法
・テーブル間のカラム定義比較
・ALL_TAB_COLUMNS の主要列の一覧
・USER_TAB_COLUMNS / ALL_TAB_COLUMNS / DBA_TAB_COLUMNS の使い分け
・カラム名の完全一致・部分一致・正規表現検索
・カラムのデータ型・桁数・NULL 制約・デフォルト値の確認
・特定カラムがどのテーブルに存在するか横断検索
・PL/SQL で「カラムが存在するか」を判定する方法
・テーブル間のカラム定義比較
・ALL_TAB_COLUMNS の主要列の一覧
USER / ALL / DBA の使い分け
| ビュー | 参照範囲 | 必要な権限 |
|---|---|---|
| USER_TAB_COLUMNS | 自分のスキーマのテーブルのみ | なし(全ユーザー使用可) |
| ALL_TAB_COLUMNS | 自分 + アクセス権のあるテーブル | なし(SELECT 権限があるテーブルが対象) |
| DBA_TAB_COLUMNS | データベース内の全テーブル | DBA ロール(または SELECT ANY DICTIONARY) |
迷ったら ALL_TAB_COLUMNS を使う
自分のスキーマだけでよければ USER_TAB_COLUMNS、他スキーマも含めるなら ALL_TAB_COLUMNS が安全です。DBA_TAB_COLUMNS は DBA 権限が必要ですが、SYS / SYSTEM を含む全テーブルが対象になります。
自分のスキーマだけでよければ USER_TAB_COLUMNS、他スキーマも含めるなら ALL_TAB_COLUMNS が安全です。DBA_TAB_COLUMNS は DBA 権限が必要ですが、SYS / SYSTEM を含む全テーブルが対象になります。
ALL_TAB_COLUMNS の主要列
| 列名 | 意味 | 例 |
|---|---|---|
| OWNER | テーブル所有者(スキーマ名) | HR |
| TABLE_NAME | テーブル名 | EMPLOYEES |
| COLUMN_NAME | カラム名 | EMPLOYEE_ID |
| DATA_TYPE | データ型 | NUMBER / VARCHAR2 / DATE |
| DATA_LENGTH | バイト単位の長さ | 22(NUMBER) / 100(VARCHAR2) |
| DATA_PRECISION | 数値の精度(桁数) | 10(NUMBER(10,2) の場合) |
| DATA_SCALE | 数値の小数桁 | 2(NUMBER(10,2) の場合) |
| NULLABLE | NULL 許可 | Y = NULL 可 / N = NOT NULL |
| DATA_DEFAULT | デフォルト値 | SYSDATE / 0 / NULL |
| COLUMN_ID | テーブル内のカラム順序 | 1, 2, 3, … |
| CHAR_LENGTH | 文字数単位の長さ(CHAR セマンティクス時) | 100 |
| CHAR_USED | BYTE / CHAR セマンティクス | B = BYTE / C = CHAR |
カラム名で検索する
完全一致検索
SQL(特定カラムの存在確認)
-- EMPLOYEE_ID というカラムがどのテーブルにあるか SELECT owner, table_name, column_name, data_type, nullable FROM all_tab_columns WHERE column_name = 'EMPLOYEE_ID' -- 大文字で指定 ORDER BY owner, table_name;
部分一致検索(LIKE)
SQL(カラム名の部分一致)
-- 「EMAIL」を含むカラムを検索 SELECT owner, table_name, column_name, data_type FROM all_tab_columns WHERE column_name LIKE '%EMAIL%' ORDER BY owner, table_name; -- 「_ID」で終わるカラム(主キー候補の調査) SELECT owner, table_name, column_name FROM all_tab_columns WHERE column_name LIKE '%\_ID' ESCAPE '\' ORDER BY owner, table_name;
正規表現検索(REGEXP_LIKE)
SQL(正規表現でカラム名を検索)
-- DATE / TIME / TIMESTAMP を含むカラムを一括検索 SELECT owner, table_name, column_name, data_type FROM all_tab_columns WHERE REGEXP_LIKE(column_name, '(DATE|TIME|TIMESTAMP)') ORDER BY owner, table_name; -- 連番サフィックス付きカラム(ADDR1, ADDR2, ADDR3 等) SELECT owner, table_name, column_name FROM all_tab_columns WHERE REGEXP_LIKE(column_name, '^ADDR[0-9]+$') ORDER BY owner, table_name, column_name;
カラム名は大文字で格納されている
Oracle はカラム名を内部的に大文字で格納します。検索時は
Oracle はカラム名を内部的に大文字で格納します。検索時は
WHERE column_name = 'EMPLOYEE_ID' のように大文字で指定してください。ダブルクォートで作成した場合("myColumn")のみ、そのままの大文字小文字で格納されます。特定テーブルのカラム一覧を取得する
SQL(テーブルの全カラム情報)
-- EMPLOYEES テーブルの全カラム情報
SELECT column_name, data_type,
CASE
WHEN data_type = 'NUMBER' AND data_precision IS NOT NULL
THEN data_type || '(' || data_precision || ',' || NVL(data_scale, 0) || ')'
WHEN data_type IN ('VARCHAR2', 'CHAR', 'NVARCHAR2')
THEN data_type || '(' || char_length || CASE char_used WHEN 'C' THEN ' CHAR' ELSE '' END || ')'
ELSE data_type
END AS full_type,
nullable,
data_default,
column_id
FROM all_tab_columns
WHERE owner = 'HR' AND table_name = 'EMPLOYEES'
ORDER BY column_id;
SQL(DESC コマンドの代替: SQL で実行可能)
-- SQL*Plus の DESC と同等の情報
SELECT column_name AS "Name",
CASE nullable WHEN 'Y' THEN NULL ELSE 'NOT NULL' END AS "Null?",
CASE
WHEN data_type LIKE '%CHAR%'
THEN data_type || '(' || char_length || ')'
WHEN data_type = 'NUMBER' AND data_precision IS NOT NULL
THEN 'NUMBER(' || data_precision || ',' || data_scale || ')'
ELSE data_type
END AS "Type"
FROM all_tab_columns
WHERE owner = 'HR' AND table_name = 'EMPLOYEES'
ORDER BY column_id;
データ型で検索する
SQL(特定のデータ型のカラムを横断検索)
-- DATE 型の全カラム(日付関連のカラムを一括検出)
SELECT owner, table_name, column_name
FROM all_tab_columns
WHERE data_type = 'DATE'
AND owner NOT IN ('SYS', 'SYSTEM', 'XDB')
ORDER BY owner, table_name;
-- CLOB / BLOB を含むテーブル(LOB 管理の調査)
SELECT owner, table_name, column_name, data_type
FROM all_tab_columns
WHERE data_type IN ('CLOB', 'BLOB', 'NCLOB')
AND owner NOT IN ('SYS', 'SYSTEM')
ORDER BY owner, table_name;
-- VARCHAR2(4000) の列(長すぎるかもしれない列の調査)
SELECT owner, table_name, column_name, char_length
FROM all_tab_columns
WHERE data_type = 'VARCHAR2' AND char_length >= 4000
AND owner NOT IN ('SYS', 'SYSTEM')
ORDER BY char_length DESC;
NULL 制約・デフォルト値を確認する
SQL(NOT NULL カラムの一覧)
-- 特定テーブルの NOT NULL カラム SELECT column_name, data_type, nullable, data_default FROM all_tab_columns WHERE owner = 'HR' AND table_name = 'EMPLOYEES' AND nullable = 'N' ORDER BY column_id;
SQL(デフォルト値が設定されているカラム)
-- デフォルト値があるカラムを検索 SELECT owner, table_name, column_name, data_default FROM all_tab_columns WHERE data_default IS NOT NULL AND owner = 'HR' ORDER BY table_name, column_id;
複数テーブルにまたがるカラム横断検索
SQL(同名カラムがどのテーブルにあるか一覧)
-- DEPARTMENT_ID が含まれる全テーブル
SELECT owner, table_name, column_name, data_type, nullable
FROM all_tab_columns
WHERE column_name = 'DEPARTMENT_ID'
AND owner NOT IN ('SYS', 'SYSTEM')
ORDER BY owner, table_name;
-- テーブル数も集計
SELECT column_name, COUNT(*) AS table_count
FROM all_tab_columns
WHERE column_name = 'DEPARTMENT_ID'
AND owner NOT IN ('SYS', 'SYSTEM')
GROUP BY column_name;
SQL(カラム名の命名規則チェック: _ID で終わらない主キー候補)
-- 主キー制約のカラムで _ID で終わらないもの(命名規則違反の検出)
SELECT c.owner, c.table_name, cc.column_name
FROM all_constraints c
JOIN all_cons_columns cc ON c.constraint_name = cc.constraint_name AND c.owner = cc.owner
WHERE c.constraint_type = 'P'
AND cc.column_name NOT LIKE '%\_ID' ESCAPE '\'
AND c.owner NOT IN ('SYS', 'SYSTEM')
ORDER BY c.owner, c.table_name;
テーブル間のカラム定義を比較する
SQL(2 つのテーブルのカラム差分)
-- テーブル A にあってテーブル B にないカラム SELECT column_name, data_type, nullable FROM all_tab_columns WHERE owner = 'HR' AND table_name = 'EMPLOYEES' MINUS SELECT column_name, data_type, nullable FROM all_tab_columns WHERE owner = 'HR' AND table_name = 'EMPLOYEES_BACKUP'; -- 逆: B にあって A にないカラム SELECT column_name, data_type, nullable FROM all_tab_columns WHERE owner = 'HR' AND table_name = 'EMPLOYEES_BACKUP' MINUS SELECT column_name, data_type, nullable FROM all_tab_columns WHERE owner = 'HR' AND table_name = 'EMPLOYEES';
SQL(同名カラムでデータ型が異なるものを検出)
-- 同じカラム名でデータ型が異なるテーブルの組み合わせ
SELECT a.table_name AS table_a, b.table_name AS table_b,
a.column_name,
a.data_type AS type_a, b.data_type AS type_b
FROM all_tab_columns a
JOIN all_tab_columns b ON a.column_name = b.column_name
AND a.owner = b.owner
AND a.table_name < b.table_name
WHERE a.data_type <> b.data_type
AND a.owner = 'HR'
ORDER BY a.column_name, a.table_name;
マイグレーション前のカラム定義比較に活用
旧テーブルと新テーブルのカラム差分を MINUS で抽出すれば、追加・削除・型変更されたカラムを正確に把握できます。Data Pump でのスキーマ移行前の影響調査に便利です。
旧テーブルと新テーブルのカラム差分を MINUS で抽出すれば、追加・削除・型変更されたカラムを正確に把握できます。Data Pump でのスキーマ移行前の影響調査に便利です。
PL/SQL でカラムの存在を判定する
SQL(PL/SQL: カラムが存在するかチェック)
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM user_tab_columns
WHERE table_name = 'EMPLOYEES'
AND column_name = 'MIDDLE_NAME';
IF v_count = 0 THEN
-- カラムが存在しない → 追加
EXECUTE IMMEDIATE 'ALTER TABLE employees ADD (middle_name VARCHAR2(50))';
DBMS_OUTPUT.PUT_LINE('MIDDLE_NAME カラムを追加しました');
ELSE
DBMS_OUTPUT.PUT_LINE('MIDDLE_NAME カラムは既に存在します');
END IF;
END;
/
SQL(汎用関数: カラム存在チェック)
-- カラムの存在を判定する汎用関数
CREATE OR REPLACE FUNCTION column_exists(
p_table_name VARCHAR2,
p_column_name VARCHAR2
) RETURN BOOLEAN IS
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM user_tab_columns
WHERE table_name = UPPER(p_table_name)
AND column_name = UPPER(p_column_name);
RETURN v_count > 0;
END;
/
-- 使い方
BEGIN
IF column_exists('employees', 'salary') THEN
DBMS_OUTPUT.PUT_LINE('salary exists');
END IF;
END;
/
マイグレーションスクリプトでの活用
「カラムが存在しなければ ALTER TABLE ADD、存在すれば何もしない」というパターンは、冪等なマイグレーションスクリプトの定番です。上記の column_exists 関数を用意しておくとスクリプトがシンプルになります。
「カラムが存在しなければ ALTER TABLE ADD、存在すれば何もしない」というパターンは、冪等なマイグレーションスクリプトの定番です。上記の column_exists 関数を用意しておくとスクリプトがシンプルになります。
テーブルのカラム数を確認する
SQL(カラム数が多いテーブルの検出)
-- カラム数が 50 以上のテーブル(設計見直し候補)
SELECT owner, table_name, COUNT(*) AS column_count
FROM all_tab_columns
WHERE owner NOT IN ('SYS', 'SYSTEM', 'XDB')
GROUP BY owner, table_name
HAVING COUNT(*) >= 50
ORDER BY column_count DESC;
カラム定義の DDL を取得する
SQL(テーブルの DDL を取得: カラム定義込み)
-- DBMS_METADATA でテーブルの完全な DDL を取得
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES', 'HR') FROM DUAL;
-- 結果: CREATE TABLE 文(全カラム + 制約 + ストレージ属性)
実務パターン集
パターン(1): マイグレーション前の影響調査
SQL
-- 「STATUS」カラムを使っているテーブルを全て洗い出す
-- (STATUS の型変更を検討しているため影響範囲を調査)
SELECT owner, table_name, data_type, nullable, char_length
FROM all_tab_columns
WHERE column_name = 'STATUS'
AND owner NOT IN ('SYS', 'SYSTEM', 'XDB')
ORDER BY owner, table_name;
パターン(2): 特定テーブルにカラムが存在するか確認
SQL
-- EMPLOYEES テーブルに HIRE_DATE カラムがあるか SELECT CASE WHEN COUNT(*) > 0 THEN 'EXISTS' ELSE 'NOT FOUND' END AS result FROM user_tab_columns WHERE table_name = 'EMPLOYEES' AND column_name = 'HIRE_DATE';
パターン(3): テーブル設計のレビュー(命名規則 + 型の統一チェック)
SQL
-- 同じカラム名なのに型が異なるケースを検出(設計不整合)
SELECT column_name, data_type, COUNT(*) AS table_count
FROM all_tab_columns
WHERE owner = 'HR'
GROUP BY column_name, data_type
HAVING column_name IN (
SELECT column_name FROM all_tab_columns
WHERE owner = 'HR'
GROUP BY column_name
HAVING COUNT(DISTINCT data_type) > 1
)
ORDER BY column_name, data_type;
-- 例: DEPARTMENT_ID が NUMBER と VARCHAR2 で混在 → 設計不整合
パターン(4): ビューも含めたカラム検索
SQL
-- ALL_TAB_COLUMNS はテーブル + ビューの両方を含む -- テーブルだけに絞るには ALL_TABLES と JOIN SELECT c.owner, c.table_name, c.column_name, c.data_type FROM all_tab_columns c JOIN all_tables t ON c.owner = t.owner AND c.table_name = t.table_name WHERE c.column_name = 'EMPLOYEE_ID' ORDER BY c.owner, c.table_name; -- ビューだけに絞る場合 SELECT c.owner, c.table_name, c.column_name FROM all_tab_columns c JOIN all_views v ON c.owner = v.owner AND c.table_name = v.view_name WHERE c.column_name = 'EMPLOYEE_ID';
よくある質問
QALL_TAB_COLUMNS にはビューのカラムも含まれますか?
Aはい。
ALL_TAB_COLUMNS はテーブルとビューの両方のカラムを返します。テーブルだけに限定したい場合は ALL_TABLES と JOIN してフィルタしてください。Qカラム名が小文字で検索しても見つかりません
AOracle はカラム名を内部的に大文字で格納します。
WHERE column_name = 'employee_id'(小文字)では見つかりません。WHERE column_name = 'EMPLOYEE_ID'(大文字)で検索するか、WHERE UPPER(column_name) = 'EMPLOYEE_ID' としてください。QUSER_TAB_COLUMNS と ALL_TAB_COLUMNS の違いは?
A
USER_TAB_COLUMNS は自分のスキーマのテーブルのみ、ALL_TAB_COLUMNS は自分 + SELECT 権限のある他スキーマのテーブルを返します。OWNER 列で所有者を確認できるのは ALL / DBA のみです。QDATA_DEFAULT 列が NULL なのにデフォルト値があるように見えます
A
DATA_DEFAULT は LONG 型で格納されるため、SQL ツールによっては正しく表示されないことがあります。TO_LOB(DATA_DEFAULT) で CLOB に変換するか、DBMS_METADATA.GET_DDL でテーブル DDL を取得して確認してください。Q仮想列(Virtual Column)も表示されますか?
Aはい。仮想列(Generated Column)も ALL_TAB_COLUMNS に含まれます。
VIRTUAL_COLUMN 列(12c 以降)が YES なら仮想列です。11g では DATA_DEFAULT に計算式が入っているかで判断できます。QALL_TAB_COLUMNS の検索が遅いです
A
ALL_TAB_COLUMNS は内部的に権限チェックを行うため、DBA_TAB_COLUMNS より遅い場合があります。DBA 権限があれば DBA_TAB_COLUMNS の方が高速です。また WHERE owner = 'HR' のようにスキーマを絞ると大幅に速くなります。まとめ
カラム情報の確認方法をまとめます。
| やりたいこと | SQL |
|---|---|
| 特定カラムがどのテーブルにあるか | SELECT owner, table_name FROM all_tab_columns WHERE column_name = ‘COL_NAME’ |
| カラム名の部分一致検索 | WHERE column_name LIKE ‘%KEYWORD%’ |
| テーブルの全カラム情報 | WHERE owner = ‘HR’ AND table_name = ‘TABLE’ ORDER BY column_id |
| NOT NULL カラムの一覧 | WHERE table_name = ‘TABLE’ AND nullable = ‘N’ |
| データ型で横断検索 | WHERE data_type = ‘DATE’ / ‘CLOB’ / ‘NUMBER’ |
| PL/SQL でカラム存在チェック | SELECT COUNT(*) INTO v FROM user_tab_columns WHERE … |
| テーブル間のカラム差分 | SELECT … FROM all_tab_columns WHERE table=A MINUS SELECT … WHERE table=B |
| テーブルの DDL を取得 | DBMS_METADATA.GET_DDL(‘TABLE’, ‘TABLE_NAME’, ‘OWNER’) |
テーブルの作成方法は「テーブルを作成する方法」、ALTER TABLE は「ALTER TABLE 完全ガイド」も併せて参照してください。

