SQL Server MERGE statement usage and examples

By:   |   Updated: 2018-03-12   |   Comments (3)   |   Related: 1 | 2 | 3 | 4 | 5 | 6 | 7 | > TSQL


Problem

In the world of software development, SQL Server developers face issues when it comes to having to perform multiple Insert and Update statements. To overcome this problem there is an option to use the MERGE statement in SQL Server that allows you to do this all at once. This tip will show the usage of the MERGE statement over separate INSERT and UPDATE statements in SQL.

Solution

We will create some sample tables and data and then show how to do an INSERT and UPDATE then show how to use MERGE to do the same thing with one statement.

Create Sample Data

The following code with DDL and DML statements is used to prepare data for this example. Two tables, Sales1 and Sales2, will be created:

  • Table Sales1 is made up of:
    • Six fields - PersonId, LastName, FirstName, Address, Amount, Payment_Mode
    • Five rows - PersonId values 11-15
  • Table Sales2 is made up of:
    • Six fields - PersonId, LastName, FirstName, Address, Amount, Payment_Mode
    • Six rows - PersonID values 1-5, 11. (with one matching record - PersonID 11).
-- script 1 - create sample tables and data

IF OBJECT_ID ('sales1','U') IS NOT NULL
    DROP TABLE sales1;
GO
/****** CREATE Sales1 ONE TABLE ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sales1](
            [PersonID] [float] NULL,
            [LastName] [nvarchar](255) NULL,
            [FirstName] [nvarchar](255) NULL,
            [Address] [nvarchar](255) NULL,
            [Amount] [float] NULL,
            [Payment_Mode] [nvarchar](255) NULL
) ON [PRIMARY]
GO

/****** CREATE Sales2 ONE TABLE ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID ('sales2','U') IS NOT NULL
    DROP TABLE sales2;
GO
CREATE TABLE [dbo].[Sales2](
            [PersonID] [float] NULL,
            [LastName] [nvarchar](255) NULL,
            [FirstName] [nvarchar](255) NULL,
            [Address] [nvarchar](255) NULL,
            [Amount] [float] NULL,
            [Payment_Mode] [nvarchar](255) NULL
) ON [PRIMARY]
GO
 
INSERT INTO [dbo].[Sales1]
           ([PersonID]
           ,[LastName]
           ,[FirstName]
           ,[Address]
           ,[Amount]
           ,[Payment_Mode])
Values
('11','Sales1LN1','Sales1FN2','Sales1ADD2','11','CASH'),
('12','Sales1LN2','Sales1FN2','Sales1ADD2','12','CASH'),
('13','Sales1LN2','Sales1FN2','Sales1ADD2','13','CASH'),
('14','Sales1LN2','Sales1FN2','Sales1ADD2','14','CASH'),
('15','Sales1LN2','Sales1FN2','Sales1ADD2','15','CASH')
 
INSERT INTO [dbo].[Sales2]
           ([PersonID]
           ,[LastName]
           ,[FirstName]
           ,[Address]
           ,[Amount]
           ,[Payment_Mode])
Values
('1','Sales2LN1','Sales2FN2','Sales2ADD2','11','CASH'),
('2','Sales2LN1','Sales2FN2','Sales2ADD2','12','CASH'),
('3','Sales2LN2','Sales2FN2','Sales2ADD2','13','CASH'),
('4','Sales2LN2','Sales2FN2','Sales2ADD2','14','CASH'),
('5','Sales2LN2','Sales2FN2','Sales2ADD2','15','CASH'),
('11','Sales2LN2','Sales2FN2','Sales2ADD2','11','CASH')
			

Sales1 Data

SELECT * FROM sales1			

Sales1 table output:

Person Id Last Name First Name Address Amount Mode
11 Sales1LN1 Sales1FN2 Sales1ADD2 11 CASH
12 Sales1LN2 Sales1FN2 Sales1ADD2 12 CASH
13 Sales1LN2 Sales1FN2 Sales1ADD2 13 CASH
14 Sales1LN2 Sales1FN2 Sales1ADD2 14 CASH
15 Sales1LN2 Sales1FN2 Sales1ADD2 15 CASH

Sales2 Data

SELECT * FROM sales2		

Sales2 table output:

Person Id Last Name First Name Address Amount Mode
1 Sales2LN1 Sales2FN2 Sales2ADD2 11 CASH
2 Sales2LN1 Sales2FN2 Sales2ADD2 12 CASH
3 Sales2LN2 Sales2FN2 Sales2ADD2 13 CASH
4 Sales2LN2 Sales2FN2 Sales2ADD2 14 CASH
5 Sales2LN2 Sales2FN2 Sales2ADD2 15 CASH
11 Sales2LN2 Sales2FN2 Sales2ADD2 11 CASH

The goal is to get Sales1 updated with any differences in Sales2 and to also add rows to Sales1 that only exist in Sales2.

INSERT and UPDATE Usage (without MERGE)

In this section, the code performs an UPDATE operation to match data between Sales1 and Sales2 tables using PersonID. We know that PersonId 11 is in both tables, so we will focus on that data.

UPDATE tab1
SET tab1.LastName = tab2.LastName ,
    tab1.FirstName = tab2.FirstName ,
    tab1.address = tab2.address
FROM Sales1 AS tab1
    INNER JOIN
    Sales2 AS tab2
        ON tab1.personid = tab2.personid;
			

Now let's look at what the data looks like after the update.

SELECT * FROM sales1 WHERE PersonID = 11			

In the table below (Sales1) we observed that the LastName, FirstName, Address in the Sales 1 are all updated to match value(s) (PersonId 11 in this case) from Sales2.

Person Id Last Name First Name Address Amount Mode
11 Sales2LN2 Sales2FN2 Sales2ADD2 11 CASH

Following the update to Sales1 for matching records, the code below performs an INSERT operation of non-matching rows from Sales2 into Sales1.

INSERT INTO sales1
SELECT *
FROM sales2
WHERE personid NOT IN ( SELECT personid FROM sales1 );
			

Now let's look at what the data looks like after the update and insert.

SELECT * FROM sales1			

The below is the output at the end of INSERT and UPDATE operations on the Sales1 table. Note that the Sales1 table now contains 10 records:

  • Retaining all the records that were initially inserted during setup
  • Updated with values from Sales2 table for a matching PersonId in Sales1 (achieved through an UPDATE operation).
  • Inserting 5 records from Sales2 table where PersonId was not present in Sales1 table (achieved through an insert operation).
Person Id Last Name First Name Address Amount Mode
11 Sales2LN2 Sales2FN2 Sales2ADD2 11 CASH
12 Sales1LN2 Sales1FN2 Sales1ADD2 12 CASH
13 Sales1LN2 Sales1FN2 Sales1ADD2 13 CASH
14 Sales1LN2 Sales1FN2 Sales1ADD2 14 CASH
15 Sales1LN2 Sales1FN2 Sales1ADD2 15 CASH
1 Sales2LN1 Sales2FN2 Sales2ADD2 11 CASH
2 Sales2LN1 Sales2FN2 Sales2ADD2 12 CASH
3 Sales2LN2 Sales2FN2 Sales2ADD2 13 CASH
4 Sales2LN2 Sales2FN2 Sales2ADD2 14 CASH
5 Sales2LN2 Sales2FN2 Sales2ADD2 15 CASH

Using the MERGE Statement

Before we run this, rerun Script 1 above to drop the tables and recreate the original data.

The MERGE statement usually involves two tables, the Source (Sales2 in our example) and the Target tables (Sales1) with the operation performed based on a common column - PersonID in this illustration.

The below code is an illustration for using the MERGE statement to perform more than one operation.

Merge into sales1 as tab1 
using(select * from Sales2) as tab2 
   on tab1.PersonID=tab2.PersonID 
when matched then 
   update set 
   tab1.lastname=tab2.lastname, 
   tab1.FirstName=tab2.FirstName, 
   tab1.Address=tab2.Address, 
   tab1.Amount=tab2.Amount, 
   tab1.Payment_Mode=tab2.Payment_Mode 
when not matched then 
   insert values(tab2.PersonID,tab2.LastName,tab2.FirstName,tab2.Address,tab2.Amount,tab2.payment_mode); 
			

If you notice in the above example the columns mapped are lastname, firstname, address, amount and payment_mod. The first set is UPDATE statement with a join using sales1.personid with sales2.personid. The next set of the statement is the INSERT, the insert will use the same columns as used in update and will insert all the non-matching rows between sales1 and sales2 table.

After running the above code, let's look at the merged data.

SELECT * FROM sales1		
Person Id Last Name First Name Address Amount Mode
11 Sales2LN2 Sales2FN2 Sales2ADD2 11 CASH
12 Sales1LN2 Sales1FN2 Sales1ADD2 12 CASH
13 Sales1LN2 Sales1FN2 Sales1ADD2 13 CASH
14 Sales1LN2 Sales1FN2 Sales1ADD2 14 CASH
15 Sales1LN2 Sales1FN2 Sales1ADD2 15 CASH
1 Sales2LN1 Sales2FN2 Sales2ADD2 11 CASH
2 Sales2LN1 Sales2FN2 Sales2ADD2 12 CASH
3 Sales2LN2 Sales2FN2 Sales2ADD2 13 CASH
4 Sales2LN2 Sales2FN2 Sales2ADD2 14 CASH
5 Sales2LN2 Sales2FN2 Sales2ADD2 15 CASH

We observe that in the MERGE statement above, both INSERT and UPDATE operations are performed in a single step, that was previously performed as two separate (UPDATE / INSERT) operations.

Next Steps


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Jayendra Viswanathan Jayendra is a Project Leader with many years of IT experience. He has strong knowledge in software development and project management.

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips


Article Last Updated: 2018-03-12

Comments For This Article




Wednesday, September 26, 2018 - 1:17:34 PM - GWB Back To Top (77734)

 Be cautious of the limitations and unfixed issues:

https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/


Wednesday, September 26, 2018 - 11:23:11 AM - Eric Back To Top (77733)

Don't forget about the "OUTPUT" clause.  Piping the output to a table enables you to quickly get counts of rows updated, inserted, and/or deleted.  I use it for our ETL logging system.


Tuesday, June 12, 2018 - 9:05:47 AM - Jorge L Rosado Back To Top (76193)

 

 Which versions and editions of MS SQL can run Merge ?  Great tip!















get free sql tips
agree to terms