MERGE
Merge is a Data Manipulation Language that allows you to perform multiple DML operations in a very efficient manner. Some calls it UPSERT also. Merge reduces the multiple IF-statements and the costly full table scan for each "IF" statement. It took me few years before I started using Merge statement to my code. Once you start using it, you will not go back to If-MESS again.
Using MERGE statement to select rows from one or more sources for update, delete or insertions from a destination table or view. This will avoid multiple INSERT, UPDATE, and DELETE DML operations and makes less overhead to your database engine by less I/O.
The Merge Syntax consist of 5 primary clauses:
1) The MERGE clause specifies the table or view that is the target of the insert, update, or delete operations.
2) The USING clause specifies the data source being joined with the target.
3) The ON clause specifies the join conditions that determine where the target and source match.
4) The WHEN clauses (WHEN MATCHED, WHEN NOT MATCHED BY TARGET, and WHEN NOT MATCHED BY SOURCE) specify the actions to take based on the results of the ON clause and any additional search criteria specified in the WHEN clauses.
5) The OUTPUT clause returns a row for each row in the target that is inserted, updated, or deleted. This clause is optional, but useful to debug.
Sql Server :
Source Table: emp_src
CREATE TABLE [dbo].[Emp_Stage](
[ID] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Salary] [int] NOT NULL,
[Start_date] [nchar](10) NOT NULL,
[City] [nvarchar](50) NOT NULL,
[Region] [char](1) NOT NULL
) ON [PRIMARY]
--Insert test data.
insert into.Emp_Stage (ID, name, salary, start_date, city, region)
values (1, 'Jason', 40420, '02/01/94', 'New York', 'W');
insert into Emp_Stage (ID, name, salary, start_date, city, region)
values (2, 'Robert',14420, '01/02/95', 'Vancouver','N');
insert into Emp_Stage (ID, name, salary, start_date, city, region)
values (3, 'Celia', 24020, '12/03/96', 'Toronto', 'W');
let's create Destination Table: emp_dest:
We will use Sql Server version of CTAS to create a table.
SELECT *
INTO emp_dest
FROM emp_stage
WHERE id = 0;
-- Verify your destination table;
select * from emp_dest;
The merge statement below does two things:
1) If the records are in both source and destination table, the salary of destination table gets updated.
2) If the records does not exist in destination table, the missing record gets inserted to destination table and also update the salary from source to destination.
MERGE emp_dw AS D
using (SELECT id,
name,
salary,
start_date,
city,
region
FROM emp_stage) AS S
ON D.id = s.id
WHEN matched THEN
UPDATE SET D.salary = S.salary
WHEN NOT matched THEN
INSERT (id,
name,
salary,
start_date,
city,
region)
VALUES (S.id,
S.name,
S.salary,
S.start_date,
S.city,
S.region);
Running the above command for the first time will copy everything from source table to destination. Adding a new record at source
table and re-running a merge will insert new record to destination table and also update salary column. You can perform the test by modifying source data like salary and/or by adding a new records. You must re-run Merge after source modifying a source data.
Additional Information:
It is important to understand how the source and target data are merged into a single input stream and how additional search criteria can be used to correctly filter out unneeded rows. Otherwise,you might specify the additional search criteria in a way that produces incorrect results.
Rows in the source are matched with rows in the target based on the join predicate specified in the ON clause. The result is a combined input stream. One insert, update, or delete operation is performed per input row. Depending on the WHEN clauses specified in the statement, the input row might be any one of the following:
- A matched pair consisting of one row from the target and one from the source. This is the result of the WHEN MATCHED clause.
- A row from the source that has no corresponding row in the target. This is the result of the WHEN NOT MATCHED BY TARGET clause.
- A row from the target that has no corresponding row in the source. This is the result of the WHEN NOT MATCHED BY SOURCE clause.
- Syntax:
USE tempdb;
GO
BEGIN TRAN;
MERGE Target AS T
USING Source AS S
ON (T.EmployeeID = S.EmployeeID AND T.EmployeeName LIKE 'S%'
AND S.EmployeeName LIKE 'S%' )
WHEN NOT MATCHED BY TARGET
THEN INSERT(EmployeeID, EmployeeName) VALUES(S.EmployeeID, S.EmployeeName)
WHEN MATCHED
THEN UPDATE SET T.EmployeeName = S.EmployeeName
WHEN NOT MATCHED BY SOURCE
THEN DELETE
OUTPUT $action, Inserted.*, Deleted.*;
ROLLBACK TRAN;
GO
Oracle DB:
Good News To Oracle user, the same syntax works for Oracle.
Oracle Example from Oracle Doc:
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
179 620
173 610
165 680
166 640
164 720
172 730
167 620
171 740
I ask you to go over your company legacy code and update that with MERGE where possible. The use of Merge makes your code optimized, faster, and more maintainable and that is what your client and your boss wants, correct?
If you are crazy and need to know more on MERGE, you can visit Oracle doc or Microsoft document page.
Interested in working with me? I can be reached at pbaniya04[at]gmail.com for any questions, consulting opportunities or you may drop a line to say HELLO. Thank your again for visiting my blog and looking forward to serving you more.
Have a Database-ious Day!
Have a Database-ious Day!
No comments