Data Pump Import(impdp)で既存のテーブルがある環境にインポートする場合、既存データを上書きしたくないケースがあります。table_exists_action=SKIP を指定すれば、既に存在するテーブルはスキップし、存在しないテーブルだけをインポートできます。
本記事では、SKIP の動作と注意点、ORA-31684 エラーとの関係、スキップされたテーブルの確認方法、不足テーブルだけ追加するパターン、そして 4 つの table_exists_action の使い分けまで解説します。
この記事でわかること
・table_exists_action=SKIP の動作
・SKIP がデフォルトである理由と ORA-31684 の関係
・スキップされたテーブルをログで確認する方法
・SKIP で「不足テーブルだけ追加」するパターン
・SKIP / REPLACE / APPEND / TRUNCATE の使い分け判断フロー
・content=DATA_ONLY / METADATA_ONLY との組み合わせ
・table_exists_action=SKIP の動作
・SKIP がデフォルトである理由と ORA-31684 の関係
・スキップされたテーブルをログで確認する方法
・SKIP で「不足テーブルだけ追加」するパターン
・SKIP / REPLACE / APPEND / TRUNCATE の使い分け判断フロー
・content=DATA_ONLY / METADATA_ONLY との組み合わせ
table_exists_action=SKIP の動作
Shell(SKIP の基本)
# 既存テーブルをスキップしてインポート(デフォルト動作)
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_export.dmp \
logfile=hr_import.log \
schemas=HR \
table_exists_action=SKIP
# table_exists_action を省略しても SKIP がデフォルト
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_export.dmp \
schemas=HR
| テーブル | 移行先に存在 | SKIP の動作 |
|---|---|---|
| EMPLOYEES | あり | スキップ(何もしない) |
| DEPARTMENTS | あり | スキップ(何もしない) |
| NEW_TABLE | なし | 作成 + データ投入 |
SKIP は「存在しないテーブルだけ追加」する動作
既存テーブルは一切変更せず、ダンプに含まれていて移行先に存在しないテーブルだけが作成されます。既存データを保護する最も安全なオプションです。
既存テーブルは一切変更せず、ダンプに含まれていて移行先に存在しないテーブルだけが作成されます。既存データを保護する最も安全なオプションです。
ORA-31684 と SKIP の関係
ログ出力例(ORA-31684)
ORA-31684: Object type TABLE:"HR"."EMPLOYEES" already exists ORA-31684: Object type TABLE:"HR"."DEPARTMENTS" already exists Table "HR"."NEW_TABLE" successfully imported
ORA-31684 は「オブジェクトが既に存在する」という情報メッセージであり、エラーではありません。table_exists_action=SKIP の場合、このメッセージは「スキップしました」という正常な動作報告です。
ORA-31684 は SKIP の正常動作
impdp のログに ORA-31684 が出ても慌てる必要はありません。SKIP を指定(またはデフォルト)していれば、「既存テーブルはスキップし、存在しないテーブルだけインポートした」という意味です。ログの最後の「successfully completed」を確認してください。
impdp のログに ORA-31684 が出ても慌てる必要はありません。SKIP を指定(またはデフォルト)していれば、「既存テーブルはスキップし、存在しないテーブルだけインポートした」という意味です。ログの最後の「successfully completed」を確認してください。
スキップされたテーブルを確認する方法
Shell(ログファイルからスキップされたテーブルを抽出)
# ORA-31684 の行を grep でスキップされたテーブルを確認 grep 'ORA-31684' /oracle/dpdir/hr_import.log # 正常にインポートされたテーブルを確認 grep 'successfully imported' /oracle/dpdir/hr_import.log # スキップ数と成功数のカウント echo "Skipped: $(grep -c 'ORA-31684' /oracle/dpdir/hr_import.log)" echo "Imported: $(grep -c 'successfully imported' /oracle/dpdir/hr_import.log)"
SQL(インポート後にダンプと移行先の差分を確認)
-- ダンプに含まれるテーブル一覧を確認(sqlfile で DDL だけ出力) -- impdp hr/password directory=DP_DIR dumpfile=hr_export.dmp sqlfile=check.sql -- 移行先のテーブル一覧 SELECT table_name FROM user_tables ORDER BY table_name;
SKIP が最適なケース
| ケース | 説明 |
|---|---|
| 不足テーブルの補完 | スキーマの一部テーブルだけが欠けている環境にダンプから補完 |
| 既存データの保護 | 本番環境にインポートする際、既存テーブルを絶対に上書きしたくない |
| 冪等なインポート | 同じダンプを複数回実行しても結果が変わらない(2 回目以降は全スキップ) |
| マイグレーションの段階的実行 | 先にテーブルだけ作成、後からデータだけ追加(content 使い分け) |
table_exists_action の 4 つのオプション比較
| オプション | 既存テーブル | 既存データ | ロールバック | 用途 |
|---|---|---|---|---|
| SKIP(デフォルト) | スキップ(何もしない) | 維持される | 不要 | 既存データを保護。不足テーブルの追加 |
| REPLACE | DROP して再作成 | 全削除 | 不可(DDL) | テーブルを完全に置き換え |
| APPEND | 維持(データを追加) | 維持 + 追加 | COMMIT 前可 | 差分データの追加。主キー重複に注意 |
| TRUNCATE | 維持(TRUNCATE + 投入) | 全削除 → 投入 | 不可(DDL) | テーブル構造は維持してデータ入れ替え |
判断フロー
table_exists_action の選び方
・既存テーブルに触れたくない → SKIP
・既存テーブルを完全に置き換えたい(構造含む)→ REPLACE
・既存テーブルにデータを追加したい → APPEND
・テーブル構造は維持してデータだけ入れ替えたい → TRUNCATE
・既存テーブルに触れたくない → SKIP
・既存テーブルを完全に置き換えたい(構造含む)→ REPLACE
・既存テーブルにデータを追加したい → APPEND
・テーブル構造は維持してデータだけ入れ替えたい → TRUNCATE
table_exists_action の全オプションの詳細は「ORA-31684 完全解説」を参照してください。
SKIP と content の組み合わせ
| 組み合わせ | 動作 | 用途 |
|---|---|---|
| SKIP + content=ALL(デフォルト) | 存在しないテーブルの構造 + データを作成 | 不足テーブルの完全補完 |
| SKIP + content=METADATA_ONLY | 存在しないテーブルの構造だけ作成(データなし) | 空テーブルの補完 |
| SKIP + content=DATA_ONLY | テーブルが存在しなければエラー(CREATE しないため) | 通常は使わない組み合わせ |
Shell(不足テーブルの構造だけ補完: METADATA_ONLY + SKIP)
# 存在しないテーブルの DDL だけ実行(データは投入しない)
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_export.dmp \
schemas=HR \
content=METADATA_ONLY \
table_exists_action=SKIP
# 既存テーブル → スキップ
# 不足テーブル → CREATE TABLE のみ実行(データなし)
SKIP + DATA_ONLY は注意
content=DATA_ONLY は CREATE TABLE を実行しないため、テーブルが存在しない場合はデータの投入先がなくエラーになります。DATA_ONLY を使う場合は SKIP ではなく APPEND または TRUNCATE を使ってください。
content=DATA_ONLY は CREATE TABLE を実行しないため、テーブルが存在しない場合はデータの投入先がなくエラーになります。DATA_ONLY を使う場合は SKIP ではなく APPEND または TRUNCATE を使ってください。
EXCLUDE / INCLUDE との組み合わせ
Shell(SKIP + 特定テーブルを除外)
# 特定テーブルを除外 + 残りは SKIP で不足分だけ追加
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_export.dmp \
schemas=HR \
table_exists_action=SKIP \
exclude=TABLE:\"IN ('TEMP_LOG', 'AUDIT_OLD')\"
parfile(parfile でクォート問題を回避)
# skip_import.par
directory=DP_DIR
dumpfile=hr_export.dmp
logfile=skip_import.log
schemas=HR
table_exists_action=SKIP
exclude=TABLE:"IN ('TEMP_LOG', 'AUDIT_OLD')"
テーブル以外のオブジェクトの SKIP 動作
| オブジェクト | 既存時の動作 | 備考 |
|---|---|---|
| テーブル | SKIP(ORA-31684) | table_exists_action で制御 |
| インデックス | スキップ(ORA-31684) | テーブルがスキップされるとインデックスもスキップ |
| 制約 | スキップ(ORA-31684) | テーブルに紐づく制約もスキップ |
| ビュー | スキップ(ORA-31684) | 既存ビューは上書きされない |
| シーケンス | スキップ(ORA-31684) | 既存シーケンスの現在値は維持 |
| プロシージャ / パッケージ | 上書きされる(CREATE OR REPLACE) | 注意: PL/SQL は常に上書き |
| トリガー | 上書きされる(CREATE OR REPLACE) | 同上 |
PL/SQL(プロシージャ / ファンクション / パッケージ / トリガー)は SKIP されない
PL/SQL オブジェクトは
PL/SQL オブジェクトは
CREATE OR REPLACE で作成されるため、table_exists_action=SKIP でも上書きされます。既存の PL/SQL を保護したい場合は EXCLUDE=PROCEDURE,FUNCTION,PACKAGE,TRIGGER で除外してください。実務パターン集
パターン(1): マイグレーションで不足テーブルだけ追加
Shell
# 本番スキーマに不足しているテーブルだけ追加
impdp system/password \
directory=DP_DIR \
dumpfile=dev_schema.dmp \
schemas=HR \
table_exists_action=SKIP \
logfile=add_missing_tables.log
# ログで追加されたテーブルを確認
grep 'successfully imported' /oracle/dpdir/add_missing_tables.log
パターン(2): 安全な環境構築(冪等インポート)
Shell
# CI/CD パイプラインで毎回実行しても安全
# 1 回目: 全テーブル作成
# 2 回目以降: 全テーブルスキップ(変更なし)
impdp hr/password \
directory=DP_DIR \
dumpfile=initial_schema.dmp \
schemas=HR \
table_exists_action=SKIP \
logfile=setup.log
パターン(3): テーブル構造だけ補完(データなし)
Shell
# 検証環境に不足テーブルの構造だけ追加(データは後から投入)
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_schema.dmp \
schemas=HR \
content=METADATA_ONLY \
table_exists_action=SKIP \
exclude=PROCEDURE,FUNCTION,PACKAGE,TRIGGER
# PL/SQL は EXCLUDE で保護(上書き防止)
パターン(4): SKIP + 後から APPEND でデータ追加
Shell
# ステップ(1): 構造だけインポート(SKIP: 既存テーブルは変更なし)
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_schema.dmp \
schemas=HR \
content=METADATA_ONLY \
table_exists_action=SKIP
# ステップ(2): データだけ追加(APPEND: 既存データを維持して追加)
impdp hr/password \
directory=DP_DIR \
dumpfile=hr_schema.dmp \
schemas=HR \
content=DATA_ONLY \
table_exists_action=APPEND
よくある質問
QSKIP がデフォルトなら指定しなくてもいいですか?
Aはい。table_exists_action を省略すると SKIP がデフォルトで適用されます。ただしスクリプトに明示的に
table_exists_action=SKIP と書いた方が意図が明確になり、保守性が向上します。QSKIP でデータの更新(既存行の上書き)はできますか?
Aできません。SKIP は既存テーブルに対して一切の操作を行いません。既存行を更新したい場合は REPLACE(DROP + 再作成)、APPEND(データ追加)、TRUNCATE(データ入れ替え)を使ってください。
QORA-31684 が大量に出ますが問題ありませんか?
Atable_exists_action=SKIP の場合、ORA-31684 は正常な動作報告です。「既に存在するのでスキップした」という意味であり、エラーではありません。ログの最終行に「successfully completed」があれば問題ありません。
QPL/SQL(プロシージャ等)は SKIP で保護されますか?
A保護されません。PL/SQL は CREATE OR REPLACE で作成されるため、table_exists_action の設定に関係なく上書きされます。既存の PL/SQL を保護するには
EXCLUDE=PROCEDURE,FUNCTION,PACKAGE,TRIGGER を指定してください。QSKIP で「新しいテーブルだけ追加」した後、統計情報は収集すべきですか?
Aはい。新しく作成されたテーブルには統計情報がないため、
DBMS_STATS.GATHER_SCHEMA_STATS(USER, OPTIONS => 'GATHER EMPTY') で統計が未収集のテーブルだけ収集することを推奨します。Qビューやシーケンスも SKIP されますか?
Aはい。テーブルと同様に、既に存在するビュー・シーケンス・インデックスは ORA-31684 でスキップされます。ただし PL/SQL(プロシージャ / パッケージ / トリガー)は例外で、CREATE OR REPLACE により上書きされます。
まとめ
table_exists_action=SKIP の要点をまとめます。
| やりたいこと | 設定 |
|---|---|
| 既存テーブルを保護して不足分だけ追加 | table_exists_action=SKIP(デフォルト) |
| 不足テーブルの構造だけ追加(データなし) | SKIP + content=METADATA_ONLY |
| ORA-31684 のスキップ対象を確認 | grep ‘ORA-31684’ import.log |
| PL/SQL の上書きを防止 | EXCLUDE=PROCEDURE,FUNCTION,PACKAGE,TRIGGER |
| 冪等なインポート(何度実行しても同じ結果) | SKIP で毎回実行(2 回目以降は全スキップ) |
| データの追加(SKIP とは異なる) | table_exists_action=APPEND |
| テーブルを完全に置き換え | table_exists_action=REPLACE |
table_exists_action の全 4 オプションの詳細は「ORA-31684 完全解説」、Data Pump の基本は「Data Pump の使い方完全ガイド」、データ保護のリストア手法は「テーブルリストア時に既存データを保護する方法」も併せて参照してください。

