Oracle でテーブルやビュー、インデックス、シーケンスなどのオブジェクト定義(DDL)を SQL だけで取得したい場面は多くあります。移行スクリプト作成・バージョン管理・環境差分確認など、現場で頻繁に使われる DBMS_METADATA パッケージを、基本から実務パターンまで体系的に解説します。
- DBMS_METADATA.GET_DDL でテーブル・ビュー・インデックス等の DDL を取得する方法
- SET_TRANSFORM_PARAM で STORAGE 句や TABLESPACE 句を除去してシンプルな DDL を得る方法
- GET_DEPENDENT_DDL でテーブルに紐付く制約・インデックスをまとめて取得する方法
- OPEN/FETCH_DDL/CLOSE でスキーマ全体の DDL を一括出力する方法
- ORA-31600・ORA-39213 などのよくあるエラーの対処法
DBMS_METADATA とは
DBMS_METADATA は Oracle が標準で提供するパッケージで、データベース内のオブジェクト定義(DDL)をプログラムから取得できます。SQL*Plus や SQL Developer の「DDL 表示」機能もこのパッケージを内部で使用しています。
| 主なサブプログラム | 概要 |
|---|---|
GET_DDL |
指定した 1 つのオブジェクトの DDL を CLOB で返す |
GET_DEPENDENT_DDL |
指定オブジェクトに依存するオブジェクトの DDL を返す(制約・インデックス等) |
GET_GRANTED_DDL |
GRANT 文を取得する |
OPEN / FETCH_DDL / CLOSE |
複数オブジェクトをループで取得(スキーマ一括出力に使用) |
SET_TRANSFORM_PARAM |
DDL 出力フォーマットを制御する(STORAGE 句除去など) |
GET_DDL の基本構文
DBMS_METADATA.GET_DDL( object_type IN VARCHAR2, -- オブジェクト種別('TABLE', 'VIEW' など) name IN VARCHAR2, -- オブジェクト名 schema IN VARCHAR2 DEFAULT NULL, -- スキーマ名(省略時は現在のスキーマ) version IN VARCHAR2 DEFAULT 'COMPATIBLE', model IN VARCHAR2 DEFAULT 'ORACLE', transform IN VARCHAR2 DEFAULT 'DDL' ) RETURN CLOB;
SQL*Plus / SQLcl では CLOB の出力上限がデフォルト 80 文字です。
SET LONG 1000000 と SET PAGESIZE 0 を先に実行しないと DDL が途中で切れます。
テーブルの DDL を取得する(最もよく使う例)
-- SQL*Plus / SQLcl での前準備
SET LONG 1000000
SET PAGESIZE 0
SET LINESIZE 200
-- 自スキーマのテーブル DDL を取得
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES') FROM DUAL;
-- 他スキーマ(HR)のテーブル DDL を取得(DBA 権限が必要)
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES', 'HR') FROM DUAL;
object_type の主な種別一覧
| object_type | 対象 | 備考 |
|---|---|---|
TABLE |
テーブル | 最もよく使う |
VIEW |
ビュー | ビュー定義の SQL が取得される |
INDEX |
インデックス | 主キー制約由来は別途 CONSTRAINT |
SEQUENCE |
シーケンス | START WITH は現在値を反映(移行時は要確認) |
PROCEDURE |
ストアドプロシージャ | CREATE OR REPLACE で出力 |
FUNCTION |
ファンクション | 同上 |
PACKAGE |
パッケージ仕様部 | 本体は PACKAGE_BODY |
PACKAGE_BODY |
パッケージ本体 | 仕様部と分けて取得 |
TRIGGER |
トリガー | ENABLE/DISABLE 状態も出力 |
SYNONYM |
シノニム | PUBLIC シノニムは PUBLIC_SYNONYM |
TYPE |
オブジェクト型仕様部 | 本体は TYPE_BODY |
TYPE_BODY |
オブジェクト型本体 | |
DATABASE_LINK |
DB リンク | パスワードは取得不可 |
MATERIALIZED_VIEW |
マテリアライズドビュー | リフレッシュ設定も含む |
JOB |
DBMS_SCHEDULER ジョブ | Oracle 10g 以降 |
SET_TRANSFORM_PARAM で出力を整形する
デフォルトの GET_DDL 出力には STORAGE 句・TABLESPACE 句・PCTFREE などの物理属性が含まれ、別環境に流用しにくい場合があります。SET_TRANSFORM_PARAM でこれらを除去できます。
よく使う変換パラメータ一覧
| パラメータ名 | デフォルト | 用途 |
|---|---|---|
STORAGE |
TRUE | FALSE にすると STORAGE 句を除去 |
SEGMENT_ATTRIBUTES |
TRUE | FALSE にすると PCTFREE/PCTUSED/INITRANS 等を除去 |
TABLESPACE |
TRUE | FALSE にすると TABLESPACE 句を除去 |
CONSTRAINTS |
TRUE | FALSE にするとインライン制約(PK/UK/FK)を除去 |
REF_CONSTRAINTS |
TRUE | FALSE にすると外部キーのみ除去 |
CONSTRAINTS_AS_ALTER |
FALSE | TRUE にすると制約を ALTER TABLE で出力 |
PRETTY |
TRUE | FALSE にすると改行・インデントを除去 |
SQLTERMINATOR |
FALSE | TRUE にすると末尾に「;」を付加 |
物理属性をすべて除去してシンプルな DDL を取得
-- セッション全体に適用(以降の GET_DDL 呼び出しに有効)
BEGIN
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'TABLESPACE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
END;
/
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES') FROM DUAL;
SESSION_TRANSFORM に設定した値はセッション中ずっと有効です。元に戻すには各パラメータを TRUE(デフォルト値)に再設定してください。一時的にだけ適用したい場合は、後述の OPEN/ADD_TRANSFORM/SET_TRANSFORM_PARAM でハンドルごとに設定する方法を使います。
GET_DEPENDENT_DDL で関連オブジェクトを取得
テーブルに紐付くインデックスや制約をまとめて取得するには GET_DEPENDENT_DDL を使います。
-- テーブルに付属するインデックスを取得
SELECT DBMS_METADATA.GET_DEPENDENT_DDL('INDEX', 'EMPLOYEES', 'HR') FROM DUAL;
-- テーブルに付属する制約を取得(PK/UK/FK/CHECK)
SELECT DBMS_METADATA.GET_DEPENDENT_DDL('CONSTRAINT', 'EMPLOYEES', 'HR') FROM DUAL;
-- 参照制約(外部キー)のみ取得
SELECT DBMS_METADATA.GET_DEPENDENT_DDL('REF_CONSTRAINT', 'EMPLOYEES', 'HR') FROM DUAL;
第 1 引数はあくまで「ベーステーブルに依存するオブジェクト種別」を指定します。
'INDEX' を指定すると、そのテーブルに作成されたすべてのインデックス(主キー由来を含む)の CREATE INDEX 文が返されます。
GET_GRANTED_DDL で権限(GRANT 文)を取得
オブジェクト権限やシステム権限の GRANT 文を取得するには GET_GRANTED_DDL を使います。スキーマ移行時に権限設定を再現する際に便利です。
-- EMPLOYEES テーブルのオブジェクト権限(GRANT 文)を取得
SELECT DBMS_METADATA.GET_GRANTED_DDL('OBJECT_GRANT', 'EMPLOYEES', 'HR') FROM DUAL;
-- ユーザー HR のシステム権限(GRANT 文)を取得
SELECT DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', 'HR') FROM DUAL;
-- ユーザー HR のロール付与(GRANT 文)を取得
SELECT DBMS_METADATA.GET_GRANTED_DDL('ROLE_GRANT', 'HR') FROM DUAL;
権限が 1 件もない場合は
ORA-31608: specified object of type OBJECT_GRANT not found が発生します。EXCEPTION ブロックでハンドリングするか、dba_tab_privs で事前に件数を確認してから呼び出してください。
複数オブジェクトの DDL を一括取得
USER_OBJECTS と組み合わせて同種オブジェクトを一括出力
-- 自スキーマのすべてのテーブル DDL を取得
SET LONG 1000000
SET PAGESIZE 0
SELECT DBMS_METADATA.GET_DDL('TABLE', table_name)
FROM user_tables
ORDER BY table_name;
-- 自スキーマのすべてのビュー DDL を取得
SELECT DBMS_METADATA.GET_DDL('VIEW', view_name)
FROM user_views
ORDER BY view_name;
OPEN / FETCH_DDL / CLOSE でスキーマ全体を一括出力
より細かく制御する場合は、ハンドルベースの API を使います。フィルタや変換パラメータをハンドル単位で指定できるため、セッション設定を汚さずに済みます。
DECLARE
h NUMBER;
th NUMBER;
obj SYS.KU$_DDLS;
BEGIN
-- ハンドルをオープン(種別: TABLE)
h := DBMS_METADATA.OPEN('TABLE');
-- フィルタ: スキーマを HR に限定
DBMS_METADATA.SET_FILTER(h, 'SCHEMA', 'HR');
-- 変換ハンドルで物理属性を除去
th := DBMS_METADATA.ADD_TRANSFORM(h, 'DDL');
DBMS_METADATA.SET_TRANSFORM_PARAM(th, 'STORAGE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(th, 'SEGMENT_ATTRIBUTES', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(th, 'SQLTERMINATOR', TRUE);
-- FETCH ループで全テーブルを出力
LOOP
obj := DBMS_METADATA.FETCH_DDL(h);
EXIT WHEN obj IS NULL;
FOR i IN 1..obj.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(obj(i).ddltext);
END LOOP;
END LOOP;
DBMS_METADATA.CLOSE(h);
END;
/
FETCH_CLOB は 1 オブジェクトを CLOB として返します。FETCH_DDL は SYS.KU$_DDLS(DDL の配列型)を返し、1 回のフェッチで複数の DDL を含む場合があります(制約や依存オブジェクトを含む場合)。確実にすべてを取得するには FETCH_DDL の使用を推奨します。
実務パターン集
パターン 1:移行スクリプト自動生成(スキーマ全体)
-- すべての種別を含む移行スクリプトをコンソール出力
BEGIN
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
END;
/
-- テーブル → インデックス → ビュー → シーケンス → プロシージャ の順で出力
SELECT DBMS_METADATA.GET_DDL(object_type, object_name, owner)
FROM (
SELECT object_type, object_name, owner,
CASE object_type
WHEN 'TABLE' THEN 1
WHEN 'INDEX' THEN 2
WHEN 'VIEW' THEN 3
WHEN 'SEQUENCE' THEN 4
WHEN 'PROCEDURE' THEN 5
WHEN 'FUNCTION' THEN 6
WHEN 'PACKAGE' THEN 7
WHEN 'PACKAGE_BODY' THEN 8
WHEN 'TRIGGER' THEN 9
ELSE 10
END AS sort_order
FROM dba_objects
WHERE owner = 'HR'
AND object_type IN ('TABLE','INDEX','VIEW','SEQUENCE','PROCEDURE','FUNCTION','PACKAGE','PACKAGE_BODY','TRIGGER')
AND status = 'VALID'
)
ORDER BY sort_order, object_name;
パターン 2:特定テーブルの完全定義を一括出力(テーブル+制約+インデックス)
DECLARE
PROCEDURE print_clob(p_clob CLOB) IS
v_offset INTEGER := 1;
v_amount INTEGER := 32767;
v_buffer VARCHAR2(32767);
BEGIN
LOOP
EXIT WHEN v_offset > DBMS_LOB.GETLENGTH(p_clob);
DBMS_LOB.READ(p_clob, v_amount, v_offset, v_buffer);
DBMS_OUTPUT.PUT_LINE(v_buffer);
v_offset := v_offset + v_amount;
END LOOP;
END;
BEGIN
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
-- テーブル本体
print_clob(DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES', 'HR'));
-- インデックス
print_clob(DBMS_METADATA.GET_DEPENDENT_DDL('INDEX', 'EMPLOYEES', 'HR'));
-- 制約
print_clob(DBMS_METADATA.GET_DEPENDENT_DDL('CONSTRAINT', 'EMPLOYEES', 'HR'));
-- 外部キー
print_clob(DBMS_METADATA.GET_DEPENDENT_DDL('REF_CONSTRAINT','EMPLOYEES', 'HR'));
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLERRM);
END;
/
パターン 3:バージョン管理用に CONSTRAINTS_AS_ALTER で出力
-- 制約を ALTER TABLE 形式で分離出力(Git 管理に向く)
BEGIN
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SEGMENT_ATTRIBUTES', FALSE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'CONSTRAINTS', TRUE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'CONSTRAINTS_AS_ALTER', TRUE);
DBMS_METADATA.SET_TRANSFORM_PARAM(
DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', TRUE);
END;
/
SELECT DBMS_METADATA.GET_DDL('TABLE', 'EMPLOYEES', 'HR') FROM DUAL;
よくあるエラーと対処法
| エラー | 原因 | 対処法 |
|---|---|---|
ORA-31600 |
SET_FILTER / SET_TRANSFORM_PARAM に無効な値を指定 | パラメータ名・値のスペルを確認 |
ORA-39213 |
XDB(XML DB)スキーマが無効または不完全 | @?/rdbms/admin/catmeta.sql で再作成、または DBA に連絡 |
ORA-31603 |
指定したオブジェクトが存在しない | オブジェクト名・スキーマ名・大文字小文字を確認 |
ORA-06512 + ORA-01031 |
対象スキーマへの権限不足 | SELECT_CATALOG_ROLE または DBA ロールが必要 |
| DDL が途中で切れる | SET LONG の値が小さすぎる | SET LONG 1000000 を事前に実行 |
| オブジェクト名が見つからない | 小文字で指定している | Oracle は識別子をデフォルト大文字で管理。大文字で指定する |
必要な権限
| 操作対象 | 必要な権限 |
|---|---|
| 自スキーマのオブジェクト | 特別な権限不要(ログインユーザーの所有オブジェクトは取得可) |
| 他スキーマのオブジェクト | SELECT ANY DICTIONARY または SELECT_CATALOG_ROLE |
| FULL スキーマ一括取得 | EXP_FULL_DATABASE または DBA ロール |
よくある質問(FAQ)
GET_DDL は SQL で即座に 1 オブジェクトの DDL を取得できますが、あくまでテキスト出力です。expdp の CONTENT=METADATA_ONLY は dmp ファイルとして出力され、impdp で再インポートできます。
スキーマ移行には expdp/impdp、手動スクリプト管理や即時確認には DBMS_METADATA という使い分けが実務ではよく行われます。
DBMS_METADATA はシーケンスの現在値(NEXTVAL – INCREMENT_BY)を START WITH に出力するため、取得した DDL をそのまま別環境で実行すると大きな値から始まります。
環境移行では取得した DDL の START WITH 値を手動で 1 に書き換えるか、user_sequences ビューから LAST_NUMBER を確認した上で調整してください。
SQL*Plus の NLS_LANG 設定がデータベースの文字セットと一致していない場合に発生します。クライアント側の NLS_LANG を JAPANESE_JAPAN.AL32UTF8(DB が UTF-8 の場合)に合わせてから実行してください。
Windows では set NLS_LANG=JAPANESE_JAPAN.AL32UTF8、Linux では export NLS_LANG=JAPANESE_JAPAN.AL32UTF8 を SQL*Plus 起動前に設定します。
ORA-31608: specified object of type INDEX not found は依存オブジェクトが 0 件のときに発生します。対象テーブルにインデックスが存在しない場合や、GET_DEPENDENT_DDL の第 1 引数に間違った種別を指定した場合に起きます。
EXCEPTION ブロックで WHEN OTHERS THEN NULL; を入れてスキップするか、user_indexes WHERE table_name = '...' で事前に件数を確認してから呼び出してください。
DBMS_METADATA はビューの DDL を CREATE OR REPLACE FORCE VIEW ... として出力します。FORCE は参照先のテーブルが存在しなくても作成できるオプションです。
移行スクリプトとして使う場合はテーブル DDL より後にビュー DDL を実行する順序にすれば問題ありません。FORCE は削除せずそのまま使うのが安全です。
まとめ
| 用途 | 推奨の方法 |
|---|---|
| 1 つのオブジェクト DDL を即時確認 | GET_DDL(object_type, name, schema) |
| テーブルに紐付く制約・インデックスを取得 | GET_DEPENDENT_DDL('CONSTRAINT'/'INDEX', table, schema) |
| STORAGE/TABLESPACE 句を除去してシンプルに | SET_TRANSFORM_PARAM(SESSION_TRANSFORM, 'STORAGE', FALSE) 等 |
| 制約を ALTER TABLE 形式で出力(Git 管理向き) | SET_TRANSFORM_PARAM(SESSION_TRANSFORM, 'CONSTRAINTS_AS_ALTER', TRUE) |
| スキーマ全体を一括出力(ループ処理) | OPEN / FETCH_DDL / CLOSE + SET_FILTER |
| 移行スクリプト全自動生成 | dba_objects を JOIN して object_type ごとに順序制御 |
DBMS_METADATA を使いこなすことで、GUI ツールなしに SQL だけでスキーマ全体の DDL を抽出・整形できます。SET_TRANSFORM_PARAM で出力をシンプルに制御し、ループ処理で一括取得するパターンを覚えれば、データ移行・バージョン管理・環境差分確認のほぼすべてに対応できます。

