Oracle SQL 副問い合わせでDMLを強化!INSERT/UPDATE/DELETE活用法

Oracle Master Silver

「別テーブルの検索結果を使って、データを登録したい」

「特定の条件に合致する行だけ、別のテーブルの値を元に更新したい」

Oracle Database を操作する中で、こうした要件に直面することは日常茶飯事です。一つひとつ値を手入力したり、プログラムでループ処理を書いたりする必要はありません。副問い合わせ(サブクエリ) を活用すれば、複雑なデータ操作を SQL 1文で完結できます。

この記事では、Oracle Database 19c を対象に、DML(INSERT / UPDATE / DELETE) における副問い合わせの実装パターンと、実務でハマりやすい注意点を解説します。

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?


結論:副問い合わせ活用のポイント

時間がない方のために、DMLで副問い合わせを使う際の要点をまとめました。

  • INSERT: VALUES 句の代わりに SELECT 文を書くことで、大量データを一括登録できる(INSERT SELECT)。
  • UPDATE: SET 句で使用し、別テーブルの値をセットする。ただし、「戻り値が複数行になるとエラーになる」「条件に合致しないとNULLで更新される」 点に注意。
  • DELETE: WHERE 句で使用し、別テーブルの条件を元に削除対象を絞り込む。
  • 推奨: 複雑な条件分岐や大量データの更新を行う場合は、MERGE 文の利用も検討する。

1. 基礎知識:DMLと副問い合わせとは?

DML (Data Manipulation Language)

データベース内のデータを操作するための言語です。主なコマンドは以下の3つです。

  • INSERT: データの作成
  • UPDATE: データの更新
  • DELETE: データの削除

副問い合わせ(サブクエリ)

SQL文の中に埋め込まれた、別の SELECT 文のことです。

外側のSQL(主問い合わせ)は、内側のSQL(副問い合わせ)の結果を受け取って処理を実行します。これにより、「A表の結果を使ってB表を操作する」といった動的な処理が可能になります。


2. 検証用データの準備

本記事のすべてのSQLを実行するために、以下のテーブルとデータを作成します。

※実機(Oracle Database 19c 以降)で動作確認済みです。

前提条件:

  • 適切な権限(CREATE TABLE, UNLIMITED TABLESPACE 等)を持つユーザーで接続してください。
-- 1. 部署テーブル (departments) の作成
CREATE TABLE departments (
    department_id   NUMBER PRIMARY KEY,
    department_name VARCHAR2(50) NOT NULL
);

-- 2. 従業員テーブル (employees) の作成
CREATE TABLE employees (
    employee_id   NUMBER PRIMARY KEY,
    employee_name VARCHAR2(50) NOT NULL,
    salary        NUMBER(10, 2),
    department_id NUMBER,
    FOREIGN KEY (department_id) REFERENCES departments(department_id)
);

-- 3. データの登録
INSERT INTO departments VALUES (10, 'Sales');
INSERT INTO departments VALUES (20, 'Engineering');
INSERT INTO departments VALUES (30, 'HR');

INSERT INTO employees VALUES (1, 'Alice', 5000, 10);
INSERT INTO employees VALUES (2, 'Bob', 6000, 20);
INSERT INTO employees VALUES (3, 'Charlie', 5500, 10);
INSERT INTO employees VALUES (4, 'David', 7000, 20);
INSERT INTO employees VALUES (5, 'Eve', 4500, 30);

-- 4. 変更を確定
COMMIT;

実行結果:

SQL> SELECT * FROM departments;

DEPARTMENT_ID DEPARTMENT_NAME
------------- --------------------
10 Sales
20 Engineering
30 HR

SQL> SELECT * FROM employees;

EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID
----------- -------------------- ---------- -------------
1 Alice 5000 10
2 Bob 6000 20
3 Charlie 5500 10
4 David 7000 20
5 Eve 4500 30

3. 実践:DMLでの副問い合わせ活用

ここから、INSERT、UPDATE、DELETE それぞれのケースでの活用方法を解説します。

3.1. INSERT文での副問い合わせ (INSERT SELECT)

別テーブルの検索結果をそのままテーブルに挿入します。データ移行や集計テーブルの作成で最もよく使われる手法です。

ここでは、「Sales部門(ID=10)かつ 給与5000以上」の従業員だけを抽出して、別テーブル high_salary_employees にコピーします。

手順:

受け皿となるテーブルを作成
CREATE TABLE high_salary_employees (
    employee_id   NUMBER PRIMARY KEY,
    employee_name VARCHAR2(50),
    salary        NUMBER(10, 2)
);

副問い合わせを使ってデータを挿入
INSERT INTO high_salary_employees (employee_id, employee_name, salary)
SELECT employee_id, employee_name, salary
FROM employees
WHERE department_id = 10 
  AND salary >= 5000;
結果を確認
SELECT * FROM high_salary_employees;

実行結果:

SQL> INSERT INTO high_salary_employees (employee_id, employee_name, salary)
2 SELECT employee_id, employee_name, salary
3 FROM employees
4 WHERE department_id = 10
5 AND salary >= 5000;

2 rows created.

SQL> SELECT * FROM high_salary_employees;

EMPLOYEE_ID EMPLOYEE_NAME SALARY
----------- -------------------- ----------
1 Alice 5000
3 Charlie 5500

ポイント:

INSERT INTO … VALUES … の記述は不要です。列の並び順とデータ型が一致している必要があります。

3.2. UPDATE文での副問い合わせ

「ある条件に基づいて、別のテーブルの値で更新したい」場合に使用します。

ここでは、「Engineering部門の従業員の給与を、全社員の中の最高給与額に書き換える」 という処理を行います。

実行SQL:

UPDATE employees
SET salary = (
    -- サブクエリ1: 全社員の最高給与を取得
    SELECT MAX(salary) FROM employees
)
WHERE department_id = (
    -- サブクエリ2: Engineering部門のIDを取得
    SELECT department_id 
    FROM departments 
    WHERE department_name = 'Engineering'
);

-- 結果確認
SELECT * FROM employees WHERE department_id = 20;

実行結果:

SQL> UPDATE employees
2 SET salary = (
3 SELECT MAX(salary) FROM employees
4 )
5 WHERE department_id = (
6 SELECT department_id
7 FROM departments
8 WHERE department_name = 'Engineering'
9 );

2 rows updated.

SQL> SELECT * FROM employees WHERE department_id = 20;

EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID
----------- -------------------- ---------- -------------
2 Bob 7000 20
4 David 7000 20

解説:

  • SET 句のサブクエリは、単一の値(スカラー値)を返す必要があります。
  • WHERE 句のサブクエリで更新対象を絞り込んでいます。

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?

3.3. DELETE文での副問い合わせ

「マスタテーブルに特定の条件で存在するデータに関連する行を削除したい」場合に使用します。

ここでは、「HR部門に所属する従業員を削除」 します。

実行SQL:

DELETE FROM employees
WHERE department_id = (
    SELECT department_id 
    FROM departments 
    WHERE department_name = 'HR'
);

-- 結果確認(0件になれば成功)
SELECT * FROM employees WHERE department_id = 30;

実行結果:

SQL> DELETE FROM employees
2 WHERE department_id = (
3 SELECT department_id
4 FROM departments
5 WHERE department_name = 'HR'
6 );

1 row deleted.

SQL> SELECT * FROM employees WHERE department_id = 30;

no rows selected

ポイント:

もし「HR」部門が複数存在したり、サブクエリが複数のIDを返す可能性がある場合は、= ではなく IN 演算子を使用するのが安全です。

例: WHERE department_id IN (SELECT …)


4. トラブルシューティング(よくあるエラー)

副問い合わせを使用したDMLで頻発するエラーと対処法です。

エラーコードエラーメッセージ原因と対処
ORA-01427単一行副問合せにより2つ以上の行が戻されましたSET col = (SELECT ...) のサブクエリが複数の結果を返しています。WHERE句を厳密にするか、MAX()などで1件に絞ってください。
ORA-00913値の個数が多すぎますINSERT 句の列数と SELECT 句の列数が一致していません。列定義を確認してください。
ORA-02291親キーがありません外部キー制約のある列に、親テーブルに存在しない値を INSERT/UPDATE しようとしました。

5. 運用・セキュリティ上の注意点

実務でこれらのSQLを使用する際は、以下のリスクを考慮してください。

1. 意図しない NULL 更新 (UPDATE時の落とし穴)

UPDATE 文で相関副問い合わせ(外側の表と結合するサブクエリ)を使う際、サブクエリの結果が0件だと、対象カラムは NULL で更新されます。

これを防ぐには、更新対象を絞り込む WHERE 句に EXISTS を使うか、値を維持する工夫が必要です。

2. パフォーマンスへの影響

WHERE 句で IN (SELECT ...) を使用する場合、データ量によっては処理が重くなることがあります。その場合は EXISTS への書き換えや、結合 (JOIN) を使用した MERGE 文への変更を検討してください。

3. トランザクション制御

DML実行後は、必ず COMMIT(確定)または ROLLBACK(取り消し)を行ってください。ツールによっては自動コミットが無効になっており、他のセッションからロック待機が発生する原因になります。


6. FAQ:よくある質問

Q1. 副問い合わせの結果が「0件」だった場合、エラーになりますか?

A. ケースによります。

  • INSERT SELECT: 0件挿入され、エラーにはなりません。
  • UPDATE SET = (...): サブクエリが0件の場合、その列は NULL に更新されます(エラーにはなりません)。これが意図しない挙動であれば注意が必要です。

Q2. 複数の列を一度にUPDATEできますか?

A. はい、可能です。以下のように記述します。

UPDATE employees
SET (salary, department_id) = (
    SELECT 6000, 30 FROM dual
)
WHERE employee_id = 1;

Q3. DELETEで間違って消してしまいました。戻せますか?

A. COMMIT 前であれば ROLLBACK; で戻せます。COMMIT 後の場合は、Oracleの フラッシュバッククエリ 機能(AS OF TIMESTAMP)を使えば、過去時点のデータを参照・復旧できる可能性があります(設定に依存します)。


7. まとめ

Oracle SQL のDMLで副問い合わせを使うことで、手作業を減らし、データの整合性を保ちながら効率的な操作が可能になります。

  • INSERT SELECT はデータ移行の基本テクニック。
  • UPDATE / DELETE では、ORA-01427(複数行戻り)エラーに注意。
  • 処理対象が曖昧な場合は、必ず SELECT 文単体で実行結果を確認してから、DMLに組み込みましょう。

まずは開発環境で、今回紹介したSQLを試してみてください。慣れてきたら、より高度なデータ操作ができる MERGE 文の学習をおすすめします。


[参考]
Oracle Database SQL言語リファレンス 19c

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?

コメント

タイトルとURLをコピーしました