「別テーブルの検索結果を使って、データを登録したい」
「特定の条件に合致する行だけ、別のテーブルの値を元に更新したい」
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専門のエージェントで非公開求人をチェックしてみませんか?




コメント