Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 12»»

Stairway to T-SQL DML Level 12: Using the MERGE Statement Expand / Collapse
Author
Message
Posted Monday, August 6, 2012 3:55 AM
Ten Centuries

Ten CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen Centuries

Group: General Forum Members
Last Login: Friday, June 6, 2014 2:06 PM
Points: 1,040, Visits: 277
Comments posted to this topic are about the item Stairway to T-SQL DML Level 12: Using the MERGE Statement

Gregory A. Larsen, MVP

Need SQL Server Examples check out my website at http://www.sqlserverexamples.com
Post #1340475
Posted Thursday, December 27, 2012 2:52 AM
SSC Journeyman

SSC JourneymanSSC JourneymanSSC JourneymanSSC JourneymanSSC JourneymanSSC JourneymanSSC JourneymanSSC Journeyman

Group: General Forum Members
Last Login: Friday, June 20, 2014 4:18 AM
Points: 80, Visits: 108
An excellent primer on the MERGE statement, thank you.

Please can I point out what I believe is simply an inadvertent typo on your part? Re listing 4 you state:

"This clause tells SQL Server whenever it finds a record in the “Source” table that is not contained in the target table that it needs to perform a DELETE operation."

This should be the other way around i.e. when record is found in Target table that is not found in Source.

Great article, thanks again
Post #1400522
Posted Thursday, December 27, 2012 8:18 AM
Ten Centuries

Ten CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen CenturiesTen Centuries

Group: General Forum Members
Last Login: Friday, June 6, 2014 2:06 PM
Points: 1,040, Visits: 277
You are correct. A correction is on it way.

Greg


Gregory A. Larsen, MVP

Need SQL Server Examples check out my website at http://www.sqlserverexamples.com
Post #1400627
Posted Tuesday, January 15, 2013 11:54 PM
Forum Newbie

Forum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum Newbie

Group: General Forum Members
Last Login: Sunday, July 20, 2014 12:54 PM
Points: 1, Visits: 142
Hi Greg,

Would like to extend my sincere thanks for such beautiful and elaborate articles on SQL Server.

I have a question hovering in my mind from past few months since I have read about MERGE. Can we use multiple conditions in 'ON' clause . For example :

MERGE dbo.Sales AS T -- Target
USING dbo.NewSalesNAdjustments AS S -- Source
ON T.Id = S.Id
AND T.SalesAmount = S.SalesAmount -- Can we use this condition too in 'ON' clause ??? I did try
--to test this but I wasn't getting correct results
WHEN MATCHED THEN -- Update
UPDATE SET T.SalesAmount = S.SalesAmount
WHEN NOT MATCHED THEN -- Insert
INSERT (Id,SalesAmount) VALUES (S.Id,S.SalesAmount);

Please Advise !
Post #1407629
Posted Wednesday, January 16, 2013 5:30 AM
SSC Rookie

SSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC Rookie

Group: General Forum Members
Last Login: Thursday, July 17, 2014 12:07 PM
Points: 36, Visits: 216
you are most definitely can use AND/OR condition in the ON clause
I have been using them forever...

also you can use an AND in MATCHED stmt.
Like so:
MERGE T
Using S
ON
t.col = s.col
WHEN MATCHED AND <otherTcol = otherScol condition> THEN
Update blah blah blah

but very cautiously
that part of MERGE is not always working as desired/expected.
Post #1407774
Posted Wednesday, January 16, 2013 8:06 AM
Forum Newbie

Forum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum NewbieForum Newbie

Group: General Forum Members
Last Login: Thursday, July 24, 2014 11:43 AM
Points: 3, Visits: 103
Curious to hear from others on whether they use the MERGE command in production and what it's performance is like.

We began using it in our unit test scripts to build data for developers immediately following the database build (we're using SSDT 2012). We wanted to use MERGE so the scripts could run even if developers already had data in their database.

So, rather than having an insert script of 10,000 records, we use the Merge command along with the 10,000 rows using the VALUES statement. This is EXTREMELY slow!
It takes 30 minutes to populate a small database (5GB) vs 2-3 minutes using TRUNCATE/INSERT.

Paul
Post #1407854
Posted Wednesday, January 16, 2013 9:08 AM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Tuesday, July 22, 2014 2:22 PM
Points: 411, Visits: 1,399
Excellent article indeed. However like in most articles on merge, you do not mention the fact that merge doesn't have a where clause. i.e. if you want to use only a part of a table as the merge target because your source data set only represents a subset of the data included in the entire table, without precautions the merge statement will delete all rows that are not in your subset. As an example scenario: you've just received one supplier's list of products and want to merge this into your dbo.products table, that contains the list of products for all of your suppliers. The fully implemented merge statement will correctly insert all missing products for your supplier and also it will correctly update all products for which the supplier has changed information and it will even remove all products from your table that are no longer in the supplier's product list. BUT, it will also delete all products from your table that are from other suppliers. Most likely not what you intended! A where clause would have been very welcome here.

There are 2 ways around this:
1 - extend the source table for the merge such that it includes all existing products entries for all but the selected supplier plus the new list of products for the selected supplier, or
2 - apply some filtering on the target table.
Obviously method 1 will result in an unnecessary large amount of rows being processed by the merge statement. It can be implemented using for example a union statement, but I won't demonstrate this here. Method 2 does at first sight not seem possible because merge doesn't have a where clause. But it is still possible by using a common table expression as the target. Here's an example:
use tempdb
go

create table dbo.suppliers (
supplier_ID int not null,
supplier_name varchar(200) not null,
constraint pk_suppliers primary key clustered (supplier_id)
);

create table dbo.supplierproducts (
supplier_id int not null,
product_code varchar(20) not null,
product_name varchar(200) not null,
constraint pk_products primary key clustered (supplier_id, product_code),
constraint fk_products_supplier foreign key (supplier_id) references dbo.suppliers (supplier_id) on delete cascade on update cascade not for replication
);

insert dbo.suppliers( supplier_id, supplier_name)
values (1, 'supplier one'),
(2, 'supplier two'),
(3, 'supplier three');
go

insert dbo.supplierproducts( supplier_id, product_code, product_name)
values (1, 'apple', 'red apples'),
(1, 'pear', 'red pears'),
(1, 'rose', 'red roses'),
(2, 'apple', 'white apples'),
(2, 'pear', 'white pears'),
(3, 'apple', 'blue apples'),
(3, 'pear', 'blue pears');
go

-- Show the content of supplierproducts table before the merge.
select * from dbo.supplierproducts
go


-- Here's the new product list supplier 1 has just sent us.
-- Notice that this list only includes supplier 1's products,
-- not the products of any other suppliers.
declare @updatedproductlist table (
product_code varchar(20) not null,
product_name varchar(200) not null,
primary key (product_code)
);

insert @updatedproductlist( product_code, product_name)
values ('apple', 'red apples'),
('pear', 'green pears'),
('kiwi', 'green kiwis');


declare @supplier_id int;

select @supplier_id = 1;

with cteTarget as (
select sp.supplier_id,
sp.product_code,
sp.product_name
from dbo.supplierproducts sp
where sp.supplier_id = @supplier_id
)
merge into cteTarget trg
using @updatedproductlist src
on (src.product_code = trg.product_code)
when not matched by target
then
insert( supplier_id, product_code, product_name)
values( @supplier_id, src.product_code, src.product_name)

when matched and src.product_name <> trg.product_name
then
update
set product_name = src.product_name
when not matched by source
then
delete
output $action, inserted.*, deleted.*;


-- Show the content of supplierproducts table before the merge.
-- Note that the products of supplier 2 and 3 are unchanged.
select * from dbo.supplierproducts;





Posting Data Etiquette - Jeff Moden
Posting Performance Based Questions - Gail Shaw
Hidden RBAR - Jeff Moden
Cross Tabs and Pivots - Jeff Moden
Catch-all queries - Gail Shaw


If you don't have time to do it right, when will you have time to do it over?
Post #1407908
Posted Wednesday, January 16, 2013 9:11 AM
SSC Rookie

SSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC Rookie

Group: General Forum Members
Last Login: Thursday, July 24, 2014 1:59 PM
Points: 33, Visits: 301
paul.barbin (1/16/2013)
Curious to hear from others on whether they use the MERGE command in production and what it's performance is like.

We began using it in our unit test scripts to build data for developers immediately following the database build (we're using SSDT 2012). We wanted to use MERGE so the scripts could run even if developers already had data in their database.

So, rather than having an insert script of 10,000 records, we use the Merge command along with the 10,000 rows using the VALUES statement. This is EXTREMELY slow!
It takes 30 minutes to populate a small database (5GB) vs 2-3 minutes using TRUNCATE/INSERT.

Paul


Have you checked out MS's article (link) for MERGE optimization?

The biggest takeaway:

To improve the performance of the MERGE statement, we recommend the following index guidelines:

Create an index on the join columns in the source table that is unique and covering.

Create a unique clustered index on the join columns in the target table.


I've noticed slow performance in MERGE, but never when following these guidlines - which sometimes forces me into staging tables, but the MERGE benefits have outweighed the downsides there.
Post #1407910
Posted Wednesday, January 16, 2013 9:14 AM
SSC Rookie

SSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC RookieSSC Rookie

Group: General Forum Members
Last Login: Thursday, July 24, 2014 1:59 PM
Points: 33, Visits: 301
R.P.Rozema (1/16/2013)
Excellent article indeed. However like in most articles on merge, you do not mention the fact that merge doesn't have a where clause. i.e. if you want to use only a part of a table as the merge target because your source data set only represents a subset of the data included in the entire table, without precautions the merge statement will delete all rows that are not in your subset.


This is easily preventable by extending the "WHEN NOT MATCHED BY SOURCE" clause, ie:

WHEN NOT MATCHED BY SOURCE AND T.TypeID = 1

Post #1407915
Posted Wednesday, January 16, 2013 9:23 AM
SSCommitted

SSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommittedSSCommitted

Group: General Forum Members
Last Login: Today @ 3:53 AM
Points: 1,545, Visits: 253
In reply to paul.barbin

I have had exactly the opposite experience and i like the syntax of it.

We used MERGE, EXCEPT and INTERSECT in a few ad-hoc queries and sproc ammendments with excellent results. The last time we used merge the operation performed nearly 50 million inserts in a matter of minutes.
Post #1407926
« Prev Topic | Next Topic »

Add to briefcase 12»»

Permissions Expand / Collapse