サンプルコード:MERGEステートメント、ON DUPLICATE KEY UPDATE、CASE WHEN、PL/SQL
SQL OracleにおけるUPSERT(UPDATEまたはINSERT)
MERGEステートメントの概要
MERGE INTO target_table
USING source_table
ON (merge_condition)
WHEN MATCHED THEN
UPDATE SET column1 = value1, column2 = value2, ...
WHEN NOT MATCHED THEN
INSERT (column_list) VALUES (value_list);
各要素の説明
- target_table: UPSERTの対象となるテーブル
- source_table: UPSERTのデータソースとなるテーブルまたはサブクエリ
- merge_condition: 結合条件。
target_table
とsource_table
のレコードをどのように一致させるかを指定 - WHEN MATCHED:
merge_condition
が真の場合に実行される処理。既存レコードの更新内容を指定 - UPDATE SET: 更新する列とその値を指定
- INSERT (column_list) VALUES (value_list): 挿入する列とその値を指定
UPSERTの例
例1:従業員テーブルの更新・挿入
MERGE INTO employees
USING new_employees
ON (employees.id = new_employees.id)
WHEN MATCHED THEN
UPDATE SET
employees.name = new_employees.name,
employees.salary = new_employees.salary
WHEN NOT MATCHED THEN
INSERT (id, name, salary)
VALUES (new_employees.id, new_employees.name, new_employees.salary);
この例では、new_employees
テーブルのデータを使用して employees
テーブルを更新します。id
列で一致するレコードは更新され、一致しないレコードは新規レコードとして挿入されます。
例2:在庫管理システムにおける商品の更新・挿入
MERGE INTO products
USING new_products
ON (products.sku = new_products.sku)
WHEN MATCHED THEN
UPDATE SET
products.quantity = products.quantity + new_products.quantity
WHEN NOT MATCHED THEN
INSERT (sku, name, quantity, price)
VALUES (new_products.sku, new_products.name, new_products.quantity, new_products.price);
- UPDATEとINSERTを1つのステートメントで記述できる
- コードの簡潔化と可読性の向上
- データの整合性の維持
MERGE
ステートメントは、SQL OracleにおけるUPSERT操作に非常に便利なツールです。上記の例を参考に、実際の業務に活用してみてください。
例1:従業員テーブルの更新・挿入
-- テーブル作成
CREATE TABLE employees (
id NUMBER(10),
name VARCHAR2(50),
salary NUMBER(10,2)
);
-- データ挿入
INSERT INTO employees (id, name, salary) VALUES (1, 'John Doe', 10000);
INSERT INTO employees (id, name, salary) VALUES (2, 'Jane Doe', 12000);
-- 新しい従業員データ
CREATE TABLE new_employees (
id NUMBER(10),
name VARCHAR2(50),
salary NUMBER(10,2)
);
INSERT INTO new_employees (id, name, salary) VALUES (1, 'John Doe', 11000);
INSERT INTO new_employees (id, name, salary) VALUES (3, 'Mike Jones', 13000);
-- MERGEステートメントによる更新・挿入
MERGE INTO employees
USING new_employees
ON (employees.id = new_employees.id)
WHEN MATCHED THEN
UPDATE SET
employees.name = new_employees.name,
employees.salary = new_employees.salary
WHEN NOT MATCHED THEN
INSERT (id, name, salary)
VALUES (new_employees.id, new_employees.name, new_employees.salary);
-- 結果確認
SELECT * FROM employees;
ID | NAME | SALARY
------- | -------- | --------
1 | John Doe | 11000
2 | Jane Doe | 12000
3 | Mike Jones | 13000
例2:在庫管理システムにおける商品の更新・挿入
-- テーブル作成
CREATE TABLE products (
sku VARCHAR2(20),
name VARCHAR2(50),
quantity NUMBER(10),
price NUMBER(10,2)
);
-- データ挿入
INSERT INTO products (sku, name, quantity, price) VALUES ('ABC123', 'Product A', 10, 100);
INSERT INTO products (sku, name, quantity, price) VALUES ('DEF456', 'Product B', 20, 200);
-- 新しい商品データ
CREATE TABLE new_products (
sku VARCHAR2(20),
name VARCHAR2(50),
quantity NUMBER(10),
price NUMBER(10,2)
);
INSERT INTO new_products (sku, name, quantity, price) VALUES ('ABC123', 'Product A', 5, 110);
INSERT INTO new_products (sku, name, quantity, price) VALUES ('GHI789', 'Product C', 30, 300);
-- MERGEステートメントによる更新・挿入
MERGE INTO products
USING new_products
ON (products.sku = new_products.sku)
WHEN MATCHED THEN
UPDATE SET
products.quantity = products.quantity + new_products.quantity,
products.price = new_products.price
WHEN NOT MATCHED THEN
INSERT (sku, name, quantity, price)
VALUES (new_products.sku, new_products.name, new_products.quantity, new_products.price);
-- 結果確認
SELECT * FROM products;
結果
SKU | NAME | QUANTITY | PRICE
------- | -------- | -------- | --------
ABC123 | Product A | 15 | 110
DEF456 | Product B | 20 | 200
GHI789 | Product C | 30 | 300
上記のサンプルコードは、MERGE
ステートメントの使用方法を理解するのに役立ちます。実際の業務に合わせて、コードを修正して使用してください。
SQL OracleでUPSERTを行う他の方法
INSERT ... ON DUPLICATE KEY UPDATE
INSERT INTO target_table (column_list)
VALUES (value_list)
ON DUPLICATE KEY UPDATE
column1 = value1, column2 = value2, ...;
説明
INSERT
ステートメントを使用して、新しいレコードを挿入します。ON DUPLICATE KEY UPDATE
句を使用して、PRIMARY KEY
またはUNIQUE
制約で重複するレコードが存在する場合の処理を指定します。- 重複するレコードが存在する場合は、指定された列の値を更新します。
例
INSERT INTO employees (id, name, salary)
VALUES (1, 'John Doe', 10000)
ON DUPLICATE KEY UPDATE
name = 'John Doe',
salary = 11000;
注意点
PRIMARY KEY
またはUNIQUE
制約が設定されていない場合は、エラーが発生します。- 更新する列は、
PRIMARY KEY
またはUNIQUE
制約の一部である必要はありません。
CASE WHEN ... THEN ... END
UPDATE target_table
SET column1 =
CASE WHEN EXISTS (
SELECT * FROM source_table
WHERE source_table.id = target_table.id
) THEN
source_table.column1
ELSE
target_table.column1
END,
column2 =
CASE WHEN EXISTS (
SELECT * FROM source_table
WHERE source_table.id = target_table.id
) THEN
source_table.column2
ELSE
target_table.column2
END,
...
WHERE EXISTS (
SELECT * FROM source_table
WHERE source_table.id = target_table.id
);
INSERT INTO target_table (column_list)
SELECT *
FROM source_table
WHERE NOT EXISTS (
SELECT * FROM target_table
WHERE target_table.id = source_table.id
);
CASE WHEN ... THEN ... END
式を使用して、source_table
に存在するレコードかどうかを判断し、存在する場合はsource_table
の値を、存在しない場合はtarget_table
の値を更新します。INSERT
ステートメントを使用して、source_table
に存在してtarget_table
に存在しないレコードを挿入します。
UPDATE employees
SET name =
CASE WHEN EXISTS (
SELECT * FROM new_employees
WHERE new_employees.id = employees.id
) THEN
new_employees.name
ELSE
employees.name
END,
salary =
CASE WHEN EXISTS (
SELECT * FROM new_employees
WHERE new_employees.id = employees.id
) THEN
new_employees.salary
ELSE
employees.salary
END
WHERE EXISTS (
SELECT * FROM new_employees
WHERE new_employees.id = employees.id
);
INSERT INTO employees (id, name, salary)
SELECT *
FROM new_employees
WHERE NOT EXISTS (
SELECT * FROM employees
WHERE employees.id = new_employees.id
);
CASE WHEN ... THEN ... END
式は、複雑になりやすいので、注意が必要です。- 2つの
SELECT
サブクエリは、同じ条件で実行する必要があります。
PL/SQLを使用して、UPSERTを行うこともできます。
DECLARE
l_id NUMBER;
l_name VARCHAR2(50);
l_salary NUMBER(10,2);
BEGIN
SELECT id, name, salary
INTO l_id, l_name, l_salary
FROM new_employees
WHERE id = 1;
IF FOUND THEN
UPDATE employees
SET name = l_name,
salary = l_salary
WHERE id = l_id;
ELSE
INSERT INTO employees (id, name, salary)
VALUES (l_id, l_name, l_salary);
END IF;
END;
SELECT
ステートメントを使用して、new_employees
テーブルからレコードを取得します。- `
sql oracle merge