Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

SQLのmergeについてまとめています。

SQLのmergeの構文

mergeは、レコードのインサート時に指定した条件次第で更新または挿入を1文で実行可能なSQLです。標準SQLではないため、各DBMSによって実装が異なります。DBMSによっては、merge自体が存在せず、別の代替機能が用意されているケースもあります。

Oracleのmergeの構文

Oracleのmergeは、update/insert以外にdeleteも実行可能。マッチング条件を指定することで2テーブルの複雑な連携が可能です。

以下は、テーブルbounsesに条件マッチした場合(WHEN MATCHED)はupdateを、条件にマッチしない場合(WHEN NOT MATCHED )にはinsertを行う例です。

CREATE TABLE bonuses (employee_id NUMBER, bonus NUMBER DEFAULT 100);

INSERT INTO bonuses(employee_id)
   (SELECT e.employee_id FROM employees e, orders o
   WHERE e.employee_id = o.sales_rep_id
   GROUP BY e.employee_id); 

SELECT * FROM bonuses ORDER BY employee_id;

EMPLOYEE_ID      BONUS
----------- ----------
        153        100
        154        100
        155        100
        156        100
        158        100
        159        100
        160        100
        161        100
        163        100

MERGE INTO bonuses D
   USING (SELECT employee_id, salary, department_id FROM employees
   WHERE department_id = 80) S
   ON (D.employee_id = S.employee_id)
   WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01
     DELETE WHERE (S.salary > 8000)
   WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus)
     VALUES (S.employee_id, S.salary*.01)
     WHERE (S.salary <= 8000);

SELECT * FROM bonuses ORDER BY employee_id;

EMPLOYEE_ID      BONUS
----------- ----------
        153        180
        154        175
        155        170
        159        180
        160        175
        161        170
        164         72
        165         68
        166         64
        167         62
        171         74
        172         73
        173         61
        179         62

Oracle公式レファレンスマニュアル:MERGE

SQL Serverのmergeの構文

以下は、SQL Serverのストアドプロシジャに、mergeを組み込んだ例です。在庫数(Quantity)より注文数(OrderQty)が大きくなり在庫0になった場合にはDELETE、そうでなければ在庫から注文数を指し引いた値を在庫に数としてUPDATEします。

CREATE PROCEDURE Production.usp_UpdateInventory  
    @OrderDate datetime  
AS  
MERGE Production.ProductInventory AS target  
USING (SELECT ProductID, SUM(OrderQty) FROM Sales.SalesOrderDetail AS sod  
    JOIN Sales.SalesOrderHeader AS soh  
    ON sod.SalesOrderID = soh.SalesOrderID  
    AND soh.OrderDate = @OrderDate  
    GROUP BY ProductID) AS source (ProductID, OrderQty)  
ON (target.ProductID = source.ProductID)  
WHEN MATCHED AND target.Quantity - source.OrderQty <= 0  
    THEN DELETE  
WHEN MATCHED
    THEN UPDATE SET target.Quantity = target.Quantity - source.OrderQty,
                    target.ModifiedDate = GETDATE()  
OUTPUT $action, Inserted.ProductID, Inserted.Quantity,
    Inserted.ModifiedDate, Deleted.ProductID,  
    Deleted.Quantity, Deleted.ModifiedDate;  
GO  
  
EXECUTE Production.usp_UpdateInventory '20030501'  

参考)MERGE (Transact-SQL) – SQL Server

MySQLのmergeの構文

MySQLには、merge文は存在しません。mergeと同様の動作は、replaceまたはinsert on duplicate key updateで記述することが可能です。

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)

mysql> SELECT * FROM test; 
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

参考)MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.2.8 REPLACE 構文

insert on duplicate key updateは、キーが重複していた場合はupdateを実行します。

INSERT `employees` 
set 
	`emp_no` = 2, 
	`birth_date` = '1983-08-08', 
	`first_name` = 'Hanako', 
	`last_name` = 'Tanaka', 
	`gender` = 'F', 
	`hire_date` = '2002-04-01'
on duplicate key UPDATE
	`emp_no` = 2, 
	`birth_date` = '1983-08-08', 
	`first_name` = 'Hanako2', 
	`last_name` = 'Tanaka', 
	`gender` = 'F', 
	`hire_date` = '2002-04-01'

【関連記事】
MySQL Insert サンプルコード集 一文で一括挿入する方法とは? 

PostgreSQLのmergeの構文

PostgreSQLには、merge文は存在しません。mergeと同様の動作は、insert文にon conflictとdo updateを指定することで記述可能です。

INSERT INTO distributors (did, dname)
    VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
    ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;

関連)PostgreSQLの公式リファレンスマニュアル:INSERT

まとめ

ポテパンダの一言メモ
  • mergeは対象テーブルにデータが存在しなければinsert、存在すればupdateを実行可能。
  • マッチング条件次第で、2つのテーブルを複雑に連携可能。
  • OracleとSQL Serverでは、mergeが使用可能。MySQLやPostgreSQLでは、代替方法で実現可能

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。