【Oracle】SELECT結果を同一テーブルへINSERTする

【Oracle】SELECT結果を同一テーブルへINSERTする

記事の文字数:2120

本記事では、Oracleデータベースにおける INSERT INTO ... SELECT を用いた同一テーブルへのデータ挿入 を解説します。基本的な構文から、INSERT ALL・INSERT FIRSTといった応用的な利用法も紹介しています。

Oracleデータベースにおいて、INSERT INTO ... SELECT構文を使うことで、既存データを元に新しいデータを同じテーブルへ挿入することが可能です。例えば、売上データの複製や過去データの履歴化、または既存データをベースに派生データを生成するシナリオにおいてよく用いられます。同じテーブルを対象とする場合は注意が必要ですが、効率的に活用すれば業務処理の自動化や高速化に大きく寄与します。

前提:テーブル定義とサンプルデータ

本記事は以下データを前提に解説します。

サンプルDDL(クリックで開く)
-- テーブル作成: 部署テーブル
CREATE TABLE departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(100),
base_salary NUMBER(10,2)
);
-- テーブル作成: 従業員テーブル
CREATE TABLE employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(100),
salary NUMBER(10,2),
dept_id NUMBER REFERENCES departments(dept_id),
created_at DATE DEFAULT SYSDATE
);
-- テーブル作成: usersテーブル
CREATE TABLE users (
user_id NUMBER PRIMARY KEY,
name VARCHAR2(50),
status VARCHAR2(20)
);
-- テーブル作成: audit_logテーブル
CREATE TABLE audit_log (
user_id NUMBER,
action VARCHAR2(20),
logtime DATE
);
-- テーブル作成: report_logテーブル
CREATE TABLE report_log (
user_id NUMBER,
result VARCHAR2(20),
logtime DATE
);
-- テーブル作成: high_salaryテーブル
CREATE TABLE high_salary (
id NUMBER,
name VARCHAR2(50)
);
-- テーブル作成: low_salaryテーブル
CREATE TABLE low_salary (
id NUMBER,
name VARCHAR2(50)
);
-- サンプルデータ投入: 部署
INSERT INTO departments (dept_id, dept_name, base_salary) VALUES (10, 'Sales', '3000');
INSERT INTO departments (dept_id, dept_name, base_salary) VALUES (20, 'HR', '4000');
INSERT INTO departments (dept_id, dept_name, base_salary) VALUES (30, 'IT', '5000');
-- サンプルデータ投入: 従業員
INSERT INTO employees (emp_id, emp_name, salary, dept_id, created_at)
VALUES (1, 'Alice', 5000, 10, TO_DATE('2023-06-01','YYYY-MM-DD'));
INSERT INTO employees (emp_id, emp_name, salary, dept_id, created_at)
VALUES (2, 'Bob', 4500, 10, TO_DATE('2023-09-15','YYYY-MM-DD'));
INSERT INTO employees (emp_id, emp_name, salary, dept_id, created_at)
VALUES (3, 'Charlie', 6000, 20, TO_DATE('2024-02-20','YYYY-MM-DD'));
INSERT INTO employees (emp_id, emp_name, salary, dept_id, created_at)
VALUES (4, 'Diana', 7000, 30, TO_DATE('2024-05-10','YYYY-MM-DD'));
-- サンプルデータ投入:users
INSERT INTO users VALUES (101, 'User_A', 'ACTIVE');
INSERT INTO users VALUES (102, 'User_B', 'INACTIVE');
INSERT INTO users VALUES (103, 'User_C', 'ACTIVE');
INSERT INTO users VALUES (104, 'User_D', 'ACTIVE');
COMMIT;
テーブルデータ(クリックで開く)

departments

DEPT_IDDEPT_NAMEBASE_SALARY
10Sales3000.00
20HR4000.00
30IT5000.00

employees

EMP_IDEMP_NAMESALARYDEPT_IDCREATED_AT
1Alice5000.00102023/06/01 0:00:00
2Bob4500.00102023/09/15 0:00:00
3Charlie6000.00202024/02/20 0:00:00
4Diana7000.00302024/05/10 0:00:00

users

USER_IDNAMESTATUS
101User_AACTIVE
102User_BINACTIVE
103User_CACTIVE
104User_DACTIVE

SELECT結果を同一テーブルへINSERTする

INSERT INTO … SELECT 文の基本と同一テーブルへの適用

最もシンプルな構文は以下の通りです。

INSERT INTO employees (emp_id, emp_name, salary, dept_id)
SELECT emp_id + 1000, emp_name, salary * 1.1, dept_id
FROM employees
WHERE dept_id = '10';

employeesの登録データ例

EMP_IDEMP_NAMESALARYDEPT_IDCREATED_AT
1001Alice5500.00102025/09/23 20:12:09
1002Bob4950.00102025/09/23 20:12:09
  • ポイント:

    • SELECT句で数値計算や文字列結合を行い、データを加工して挿入できます。
    • WHERE句により、対象データを絞り込んで不要な挿入を避けられます。

複数のテーブルを結合した上でのINSERTも可能です。

INSERT INTO employees (emp_id, emp_name, salary, dept_id)
SELECT e.emp_id + 2000, e.emp_name, d.base_salary, e.dept_id
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id;

employeesの登録データ例

EMP_IDEMP_NAMESALARYDEPT_IDCREATED_AT
2001Alice3000.00102025/09/23 20:12:37
2002Bob3000.00102025/09/23 20:12:37
2003Charlie4000.00202025/09/23 20:12:37
2004Diana5000.00302025/09/23 20:12:37
3001Alice3000.00102025/09/23 20:12:37
3002Bob3000.00102025/09/23 20:12:37

このようにJOINを組み合わせることで、別テーブルの属性を参照しながら効率的にデータを生成できます。

INSERT ALLによる複数行挿入

複数のINSERTをまとめて実行できます。条件が複数に一致する場合はすべて適用されます。

INSERT ALL
INTO audit_log VALUES (user_id, 'INSERTED', sysdate)
INTO report_log VALUES (user_id, 'OK', sysdate)
SELECT user_id FROM users WHERE status = 'ACTIVE';

audit_logの登録データ例

USER_IDACTIONLOGTIME
101INSERTED2025/09/23 20:18:00
103INSERTED2025/09/23 20:18:00
104INSERTED2025/09/23 20:18:00

report_logの登録データ例

USER_IDRESULTLOGTIME
101OK2025/09/23 20:18:00
103OK2025/09/23 20:18:00
104OK2025/09/23 20:18:00

INSERT FIRSTによる複数行挿入

条件に一致した最初のものだけを評価してINSERTする構文です。

INSERT FIRST
WHEN salary > 5000 THEN INTO high_salary VALUES (emp_id, emp_name)
WHEN salary <= 5000 THEN INTO low_salary VALUES (emp_id, emp_name)
SELECT emp_id, emp_name, salary FROM employees;

high_salaryの登録データ例

IDNAME
3Charlie
4Diana
1001Alice

low_salaryの登録データ例

IDNAME
1Alice
2Bob
1002Bob
2001Alice
2002Bob
2003Charlie
2004Diana
3001Alice
3002Bob

これにより、条件分岐による振り分けINSERTが容易になります。


以上で本記事の解説を終わります。
よいITライフを!
Scroll to Top