【Oracle】指定したカラム名が存在するか確認する方法|ALL_TAB_COLUMNS・データ型・NULL制約・複数条件検索まで完全解説

【Oracle】指定したカラム名が存在するか確認する方法|ALL_TAB_COLUMNS・データ型・NULL制約・複数条件検索まで完全解説 Oracle

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 / 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 を含む全テーブルが対象になります。

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 はカラム名を内部的に大文字で格納します。検索時は 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 でのスキーマ移行前の影響調査に便利です。

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 関数を用意しておくとスクリプトがシンプルになります。

テーブルのカラム数を確認する

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 の違いは?
AUSER_TAB_COLUMNS は自分のスキーマのテーブルのみ、ALL_TAB_COLUMNS は自分 + SELECT 権限のある他スキーマのテーブルを返します。OWNER 列で所有者を確認できるのは ALL / DBA のみです。
QDATA_DEFAULT 列が NULL なのにデフォルト値があるように見えます
ADATA_DEFAULTLONG 型で格納されるため、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 の検索が遅いです
AALL_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 完全ガイド」も併せて参照してください。