
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'));
-- サンプルデータ投入:usersINSERT 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_ID | DEPT_NAME | BASE_SALARY |
---|---|---|
10 | Sales | 3000.00 |
20 | HR | 4000.00 |
30 | IT | 5000.00 |
employees
EMP_ID | EMP_NAME | SALARY | DEPT_ID | CREATED_AT |
---|---|---|---|---|
1 | Alice | 5000.00 | 10 | 2023/06/01 0:00:00 |
2 | Bob | 4500.00 | 10 | 2023/09/15 0:00:00 |
3 | Charlie | 6000.00 | 20 | 2024/02/20 0:00:00 |
4 | Diana | 7000.00 | 30 | 2024/05/10 0:00:00 |
users
USER_ID | NAME | STATUS |
---|---|---|
101 | User_A | ACTIVE |
102 | User_B | INACTIVE |
103 | User_C | ACTIVE |
104 | User_D | ACTIVE |
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_idFROM employeesWHERE dept_id = '10';
employeesの登録データ例
EMP_ID | EMP_NAME | SALARY | DEPT_ID | CREATED_AT |
---|---|---|---|---|
1001 | Alice | 5500.00 | 10 | 2025/09/23 20:12:09 |
1002 | Bob | 4950.00 | 10 | 2025/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_idFROM employees eJOIN departments d ON e.dept_id = d.dept_id;
employeesの登録データ例
EMP_ID | EMP_NAME | SALARY | DEPT_ID | CREATED_AT |
---|---|---|---|---|
2001 | Alice | 3000.00 | 10 | 2025/09/23 20:12:37 |
2002 | Bob | 3000.00 | 10 | 2025/09/23 20:12:37 |
2003 | Charlie | 4000.00 | 20 | 2025/09/23 20:12:37 |
2004 | Diana | 5000.00 | 30 | 2025/09/23 20:12:37 |
3001 | Alice | 3000.00 | 10 | 2025/09/23 20:12:37 |
3002 | Bob | 3000.00 | 10 | 2025/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_ID | ACTION | LOGTIME |
---|---|---|
101 | INSERTED | 2025/09/23 20:18:00 |
103 | INSERTED | 2025/09/23 20:18:00 |
104 | INSERTED | 2025/09/23 20:18:00 |
report_logの登録データ例
USER_ID | RESULT | LOGTIME |
---|---|---|
101 | OK | 2025/09/23 20:18:00 |
103 | OK | 2025/09/23 20:18:00 |
104 | OK | 2025/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の登録データ例
ID | NAME |
---|---|
3 | Charlie |
4 | Diana |
1001 | Alice |
low_salaryの登録データ例
ID | NAME |
---|---|
1 | Alice |
2 | Bob |
1002 | Bob |
2001 | Alice |
2002 | Bob |
2003 | Charlie |
2004 | Diana |
3001 | Alice |
3002 | Bob |
これにより、条件分岐による振り分けINSERTが容易になります。
以上で本記事の解説を終わります。
よいITライフを!