Using Case In Sql Server Update Statement With Join OracleUsing Case In Sql Server Update Statement With JoinsNOT NULL,CONSTRAINT PKMy. Adobe Acrobat 8 Text Box Font Color In Html. Customers PRIMARY KEYcustid Preventing MERGE Conflicts One of the classic tasks thats handled with the MERGE statement is update where exists and insert where not exists. Some people refer to this task as upsert. For example, suppose you have a stored procedure that accepts as input parameters the attributes of a customer custid, companyname, country, phone. The procedure is supposed to check whether the customer ID already exists in the target table Sales. My. Customers if it does exist, update the target row, overwriting the nonkey columns with the new values, and if it doesnt exist, add a new row. This task can be accomplished with the following MERGE statement MERGE INTO Sales. My. Customers AS TGTUSING VALUES custid, companyname, country, phone AS SRC custid, companyname, country, phone ON SRC. TGT. custid. WHEN MATCHED THEN UPDATESET TGT. SRC. companyname,TGT. SRC. country,TGT. SRC. phone. WHEN NOT MATCHED THEN INSERTVALUES SRC. SRC. companyname, SRC. SRC. phone The problem is that under the default isolation level, read committed, conflicts can occur if two processes execute the procedure at the same time with the same customer ID as input. If the input customer ID doesnt exist in the target table, the MERGE predicate in both cases will return a false, activating in both cases the WHEN NOT MATCHED action INSERT. In such a case, one of the inserts will result in a primary key violation. To prove this, run the code in Listing 2 from two sessions. SET NOCOUNT ON USE TSQL2. BEGIN TRY WHILE 1 1. BEGIN DECLAREcustid INT CHECKSUMSYSDATETIME,companyname NVARCHAR4. NA,country NVARCHAR1. NB,phone NVARCHAR2. NC MERGE INTO Sales. My. Customers AS TGTUSING VALUES custid, companyname, country, phone AS SRC custid, companyname, country, phone ON SRC. TGT. custid. WHEN MATCHED THEN UPDATESET TGT. SRC. companyname,TGT. SRC. country,TGT. SRC. phone. WHEN NOT MATCHED THEN INSERTVALUES SRC. SRC. companyname, SRC. SRC. phone END END TRYBEGIN CATCH THROW END CATCH SET NOCOUNT OFF The code uses an infinite loop that invokes the aforementioned MERGE statement. It uses the expression CHECKSUMSYSDATETIME to generate the customer ID. Theres a high likelihood that the resulting value doesnt already exist as a customer ID in the target table and that after some iterations both sessions will produce the same value. When I ran this code from two sessions, I got a conflict after a few seconds, and one of the sessions generated the error message in Figure 1. Note that this isnt considered a bug. The atomicity of the MERGE transaction isnt violated its still an all or nothing behavior. According to the read committed isolation level, such conflicts arent supposed to be prevented. If you want to serialize access to the object throughout the transaction both the check whether the customer exists and the insertion, you need to use the serializable isolation level. You can achieve this by either setting the sessions isolation level to serializable SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, or by specifying the table hint HOLDLOCK or SERIALIZABLE both have the same meaning against the target table. To test using the serializable isolation level alter the MERGE statement in Listing 2, replace the first line in the statement with the following MERGE INTO Sales. My. Customers WITH HOLDLOCK AS TGT Run the code from two sessions, and this time conflicts shouldnt occur. The MERGE ON Clause Isnt a Filter The MERGE statement uses an ON clause to define the MERGE predicate. However, this clause has a different meaning than the ON clause in a join which some people dont realize. In a join, the ON clause is used for both matching and filtering purposes. In a MERGE statement, the ON clause is used to identify matches and nonmatches and to accordingly determine which WHEN clause to activate. If you dont realize this, and you think of ON as a filter, you can end up writing MERGE statements with bugs. Ill demonstrate this problem with an example, and Ill provide a solution. In my example, Ill use the Sales. Customers table as the source for the MERGE statement and the Sales. My. Customers table as the target. First, run the following code to populate the Sales. My. Customers table with some rows representing customers from Sweden and Italy TRUNCATE TABLE Sales. My. Customers INSERT INTO Sales. My. Customerscustid, companyname, country, phoneSELECT custid, companyname, country, phone. FROM Sales. Customers. WHERE country IN NSweden, NItaly Next, suppose youre given a task to write a MERGE statement that merges customers from Italy from the Sales. Customers table into the Sales. My. Customers table. Youre supposed to update customers that exist, and insert customers that dont exist. But you need to work with only source customers from Italy. If you think of the MERGE ON clause as a filter, you might write a statement such as the following MERGE INTO Sales. My. Customers AS TGTUSING Sales. Customers SRCON SRC. TGT. custid. AND SRC. NItalyWHEN MATCHED THEN UPDATESET TGT. SRC. companyname,TGT. SRC. country,TGT. SRC. phone. WHEN NOT MATCHED THEN INSERTVALUES SRC. SRC. companyname, SRC. SRC. phone Try running this code, and youll get the error message in Figure 2. The reason for the error is that the ON clause isnt a filter it only determines which of the WHEN clauses to activate. This means that if the source has a customer that isnt from Italy, the ON predicate produces a false, and the row is directed to the WHEN NOT MATCHED clause. This clause attempts to insert the row into the target table. If the customer already exists in the target, you get a primary key violation error. If it doesnt exist, you end up inserting a row that youre not supposed to into the target. The solution is to do all the filtering that you need ahead of time in a table expression and use the table expression as the source for the MERGE statement. Heres an example of how you can achieve this with a CTE WITH SRC ASSELECT custid, companyname, country, phone. FROM Sales. Customers. WHERE country NItalyMERGE INTO Sales. My. Customers AS TGTUSING SRCON SRC. TGT. custid. WHEN MATCHED THEN UPDATESET TGT. SRC. companyname,TGT.