{"id":1645,"date":"2013-02-05T10:00:57","date_gmt":"2013-02-05T15:00:57","guid":{"rendered":"http:\/\/sqlity.net\/en\/?p=1645"},"modified":"2014-11-13T13:48:15","modified_gmt":"2014-11-13T18:48:15","slug":"merge-wonders-insert-or-use","status":"publish","type":"post","link":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/","title":{"rendered":"Merge Wonders \u2013 Insert or Use"},"content":{"rendered":"<div>\n<h3>Introduction<\/h3>\n<p>\nWhen working with clients I often see code that follows the insert-or-use pattern. Let's assume we have a <span class=\"tt\">dbo.Product<\/span> table:\n<\/p>\n<div>\n[sql]\nCREATE TABLE dbo.Product<br \/>\n(<br \/>\nId INT NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,<br \/>\nName NVARCHAR(50) NOT NULL,<br \/>\nProductNumber NVARCHAR(25)<br \/>\n);<br \/>\n[\/sql]\n<\/div>\n<p>\nOften the pattern is implemented like this:\n<\/p>\n<div>\n[sql]\nCREATE PROCEDURE dbo.GetOrCreateProduct<br \/>\n  @ProductName NVARCHAR(50),<br \/>\n  @ProductNumber NVARCHAR(25),<br \/>\n  @Id INT OUTPUT<br \/>\nAS<br \/>\nBEGIN<br \/>\n  IF EXISTS(SELECT 1 FROM dbo.Product WHERE ProductNumber = @ProductNumber)<br \/>\n  BEGIN<br \/>\n    SELECT @Id = Id FROM dbo.Product WHERE ProductNumber = @ProductNumber;<br \/>\n  END<br \/>\n  ELSE<br \/>\n  BEGIN<br \/>\n    INSERT INTO dbo.Product(Name, ProductNumber)VALUES(@ProductName, @ProductNumber);<br \/>\n    SELECT @id = @@IDENTITY;<br \/>\n  END;<br \/>\nEND;<br \/>\n[\/sql]\n<\/div>\n<p>\nThere are several issues with this implementation. To start the table is accessed twice in all cases. If there is no index on <span class=\"tt\">ProductNumber<\/span>, that will cause disastrous performance, but even with an index, we should avoid double work whenever possible. Even more important, in the time between the first and the second read, someone else could have inserted a row already. Depending on if there is a unique constraint on <span class=\"tt\">ProductNumber<\/span> this will then either cause a duplicate row to be created or it will cause this code to fail. Also, there is a whole slew of issues with <span class=\"tt\">@@IDENTITY<\/span>itself  that I am not going to cover today. Refer back to my <a href=\"http:\/\/sqlity.net\/en\/351\/identity-crisis\/\">Identity Crisis<\/a> post for more information.\n<\/p>\n<h3>The Merge Statement to the rescue<\/h3>\n<p>\nThere are several options to deal with the problems described above. One of the more elegant ones is the use of the <span class=\"tt\">MERGE<\/span> statement.\n<\/p>\n<p>\nThe <span class=\"tt\">MERGE<\/span> statement that was introduced in SQL Server 2008 is intended to be used in an <span class=\"tt\">INSERT<\/span> or <span class=\"tt\">UPDATE<\/span> situation.  So how does it help in this situation, where no <span class=\"tt\">UPDATE<\/span> is involved?\n<\/p>\n<p>\nLet's address the issues of the solution above one at a time to see how the <span class=\"tt\">MERGE<\/span> statement can help. Because of the issues described in the <a href=\"http:\/\/sqlity.net\/en\/351\/identity-crisis\/\">Identity Crisis<\/a> post, it is recommended to use the output clause to get the value of the identity column of a newly inserted row like this:\n<\/p>\n<div>\n[sql]\nCREATE PROCEDURE dbo.GetOrCreateProduct<br \/>\n  @ProductName NVARCHAR(50),<br \/>\n  @ProductNumber NVARCHAR(25),<br \/>\n  @Id INT OUTPUT<br \/>\nAS<br \/>\nBEGIN<br \/>\n  DECLARE @Ids TABLE(Id INT);<\/p>\n<p>  INSERT INTO dbo.Product(Name, ProductNumber)<br \/>\n  OUTPUT(INSERTED.IDENTITYCOL)INTO @Ids<br \/>\n  VALUES(@ProductName, @ProductNumber);<\/p>\n<p>  SELECT @Id = Id FROM @Ids;<br \/>\nEND;<br \/>\n[\/sql]\n<\/p><\/div>\n<p>\nThe double step of storing the identity value in a table variable and then reading it back out to use it is necessary, because SQL Servers <span class=\"tt\">OUTPUT<\/span> clause cannot directly be used to set the value of a variable.\n<\/p>\n<p>\nThis takes care of the insert portion, but we don't want to insert a new row if one exists already. That is where <span class=\"tt\">MERGE<\/span> gets introduced:\n<\/p>\n<div>\n[sql]\nCREATE PROCEDURE dbo.GetOrCreateProduct<br \/>\n  @ProductName NVARCHAR(50),<br \/>\n  @ProductNumber NVARCHAR(25),<br \/>\n  @Id INT OUTPUT<br \/>\nAS<br \/>\nBEGIN<br \/>\n  DECLARE @Ids TABLE(Id INT);<\/p>\n<p>  MERGE dbo.Product AS p<br \/>\n  USING (VALUES(@ProductName, @ProductNumber))n(Name,ProductNumber)<br \/>\n  ON p.ProductNumber = n.ProductNumber<br \/>\n  WHEN NOT MATCHED THEN<br \/>\n  INSERT(Name, ProductNumber)<br \/>\n  VALUES(n.Name, n.ProductNumber)<br \/>\n  OUTPUT(INSERTED.IDENTITYCOL)INTO @Ids<br \/>\n  ;<\/p>\n<p>  SELECT @Id = Id FROM @Ids;<br \/>\nEND;<br \/>\n[\/sql]\n<\/p><\/div>\n<p>\nNow a new row is only inserted no matching row exists. If a matching row exists the <span class=\"tt\">MERGE<\/span> statement does nothing. That however means that in that case the <span class=\"tt\">OUTPUT<\/span> clause does not return any rows, so we won't be able to retrieve the correct <span class=\"tt\">Id<\/span>. To get the <span class=\"tt\">OUTPUT<\/span> clause to return the required information, we just need to add an <span class=\"tt\">UPDATE<\/span> into the mix. If you have a column that you would like to be updated on ever access (like a column with the time of the last access) this is easily done. But what can we do if we do not actually want to change a column value? We can just assign a column to itself as in <span class=\"tt\">SET p.ProductNumber = p.ProductNumber<\/span>. SQL Server is clever enough to not actually execute the write if no changes happened. But this is a little dangerous, because the next person looking at this code might think that this was an oversight and just take out the <span class=\"tt\">UPDATE<\/span> that clearly isn't doing anything. So I like to be a little more obvious about this and instead use the ability of the <span class=\"tt\">UPDATE<\/span> statement to set variables like this:\n <\/p>\n<div>\n[sql]\nCREATE PROCEDURE dbo.GetOrCreateProduct<br \/>\n  @ProductName NVARCHAR(50),<br \/>\n  @ProductNumber NVARCHAR(25),<br \/>\n  @Id INT OUTPUT<br \/>\nAS<br \/>\nBEGIN<br \/>\n  DECLARE @Ids TABLE(Id INT);<br \/>\n  DECLARE @dummy INT;<\/p>\n<p>  MERGE dbo.Product AS p<br \/>\n  USING (VALUES(@ProductName, @ProductNumber))n(Name,ProductNumber)<br \/>\n  ON p.ProductNumber = n.ProductNumber<br \/>\n  WHEN MATCHED THEN<br \/>\n  UPDATE SET @dummy = @dummy<br \/>\n  WHEN NOT MATCHED THEN<br \/>\n  INSERT(Name, ProductNumber)<br \/>\n  VALUES(n.Name, n.ProductNumber)<br \/>\n  OUTPUT(INSERTED.IDENTITYCOL)INTO @Ids<br \/>\n  ;<\/p>\n<p>  SELECT @Id = Id FROM @Ids;<br \/>\nEND;<br \/>\n[\/sql]\n<\/p><\/div>\n<p>\nWhile it is still a little obfuscated what is happening here, at least it should be clear that the line of code with the <span class=\"tt\">UPDATE<\/span> was not an accident. You could even be more verbose and write something like this: <span class=\"tt\">UPDATE SET @this_is_a_required_update = 1<\/span>\n<\/p>\n<h3>Danger, Concurrency!<\/h3>\n<p>\nThe biggest problem with the original code is that it did not prevent concurrent inserts of the same value. If two connections at the same time execute the procedure for the same product, they both will not find the product at about the same time and then insert the product also at the same time. If there is a unique constraint on the column this will cause unexpected errors. If there is no unique constraint this will cause row duplicates, which usually is even worse.\n<\/p>\n<p>\nThe <span class=\"tt\">MERGE<\/span> statement was written for cases where a row might be inserted if it does not yet exists. So you would expect that it could handle this case automatically. However, under the covers <span class=\"tt\">MERGE<\/span> is just a lookup potentially followed by an insert. This is probably due to the <span class=\"tt\">MERGE<\/span> statement being targeted at whole table synchronizations. The name itself hints at that. In that case high frequency calls with the same values are highly unlikely and any measures to prevent the side-effects of such will unnecessarily take additional resources. That means that in our case we need to take one additional step:\n<\/p>\n<div>\n[sql]\nCREATE PROCEDURE dbo.GetOrCreateProduct<br \/>\n  @ProductName NVARCHAR(50),<br \/>\n  @ProductNumber NVARCHAR(25),<br \/>\n  @Id INT OUTPUT<br \/>\nAS<br \/>\nBEGIN<br \/>\n  DECLARE @Ids TABLE(Id INT);<br \/>\n  DECLARE @dummy INT;<\/p>\n<p>  MERGE dbo.Product WITH(HOLDLOCK) AS p<br \/>\n  USING (VALUES(@ProductName, @ProductNumber))n(Name,ProductNumber)<br \/>\n  ON p.ProductNumber = n.ProductNumber<br \/>\n  WHEN MATCHED THEN<br \/>\n  UPDATE SET @dummy = @dummy<br \/>\n  WHEN NOT MATCHED THEN<br \/>\n  INSERT(Name, ProductNumber)<br \/>\n  VALUES(n.Name, n.ProductNumber)<br \/>\n  OUTPUT(INSERTED.IDENTITYCOL)INTO @Ids<br \/>\n  ;<\/p>\n<p>  SELECT @Id = Id FROM @Ids;<br \/>\nEND;<br \/>\n[\/sql]\n<\/p><\/div>\n<p>\nThe only difference to the previous version is the <span class=\"tt\">WITH(HOLDLOCK)<\/span>  table hint right after the table name. The <span class=\"tt\">HODLOCK<\/span> table hint causes SQL Server to access that one table as if the current isolation level was set to serializable. That does prevent any insert collisions effectively. However, <span class=\"tt\">HOLDLOCK<\/span> makes use of range locks. Range locks require the search argument to be indexed, otherwise SQL Server will effectively have to take a table lock, as there is nothing of which a range could be taken. If you set the transaction isolation level to serializable and run a query that requires a table scan, SQL Server will actually take a table lock instead of many range locks. However, this is not the case when using the <span class=\"tt\">MERGE<\/span> statement together with the <span class=\"tt\">HOLDLOCK<\/span> table hint. SQL Server will instead take a range lock on every row. That has the same effect as a table lock but at a much higher cost. So it is imperative that you have appropriate indexes in place when using this solution. But that index is one that you should have anyway if you are executing this query often.\n<\/p>\n<h3>Summary<\/h3>\n<p>\nWhile not directly designed for this use case, the SQL Server <span class=\"tt\">MERGE<\/span> statement gives us an easy and &ndash;  if used correctly &ndash; safe way to deal with an Insert or Use scenario. In this scenario a row's primary key needs to be retrieved if the row exists, otherwise the row needs to be created and the newly generated identity value needs to be returned.\n<\/p>\n<p>\nWhile there are many ways to solve this problem and to circumvent all the pitfalls associated with it, <span class=\"tt\">MERGE<\/span> offers one of the most elegant solutions.\n<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.<\/p>\n<p> <a href=\"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/\">[more&#8230;]<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[5,30,33,19,23],"tags":[],"class_list":["post-1645","post","type-post","status-publish","format-standard","hentry","category-general","category-hints","category-merge","category-performance","category-t-sql-statements"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Merge Wonders \u2013 Insert or Use - sqlity.net<\/title>\n<meta name=\"description\" content=\"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Merge Wonders \u2013 Insert or Use - sqlity.net\" \/>\n<meta property=\"og:description\" content=\"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/\" \/>\n<meta property=\"og:site_name\" content=\"sqlity.net\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/sqlity.net\" \/>\n<meta property=\"article:published_time\" content=\"2013-02-05T15:00:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2014-11-13T18:48:15+00:00\" \/>\n<meta name=\"author\" content=\"Sebastian Meine\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@sqlity\" \/>\n<meta name=\"twitter:site\" content=\"@sqlity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sebastian Meine\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/\"},\"author\":{\"name\":\"Sebastian Meine\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\"},\"headline\":\"Merge Wonders \u2013 Insert or Use\",\"datePublished\":\"2013-02-05T15:00:57+00:00\",\"dateModified\":\"2014-11-13T18:48:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/\"},\"wordCount\":1431,\"commentCount\":0,\"articleSection\":[\"General\",\"Hints\",\"MERGE\",\"Performance\",\"T-SQL Statements\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/\",\"url\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/\",\"name\":\"Merge Wonders \u2013 Insert or Use - sqlity.net\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#website\"},\"datePublished\":\"2013-02-05T15:00:57+00:00\",\"dateModified\":\"2014-11-13T18:48:15+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\"},\"description\":\"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1645\\\/merge-wonders-insert-or-use\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/sqlity.net\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Merge Wonders \u2013 Insert or Use\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/sqlity.net\\\/en\\\/\",\"name\":\"sqlity.net\",\"description\":\"Quality for SQL\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/sqlity.net\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\",\"name\":\"Sebastian Meine\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"caption\":\"Sebastian Meine\"},\"sameAs\":[\"http:\\\/\\\/sqlity.net\",\"https:\\\/\\\/x.com\\\/sqlity\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Merge Wonders \u2013 Insert or Use - sqlity.net","description":"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/","og_locale":"en_US","og_type":"article","og_title":"Merge Wonders \u2013 Insert or Use - sqlity.net","og_description":"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.","og_url":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/","og_site_name":"sqlity.net","article_publisher":"https:\/\/www.facebook.com\/sqlity.net","article_published_time":"2013-02-05T15:00:57+00:00","article_modified_time":"2014-11-13T18:48:15+00:00","author":"Sebastian Meine","twitter_card":"summary_large_image","twitter_creator":"@sqlity","twitter_site":"@sqlity","twitter_misc":{"Written by":"Sebastian Meine","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/#article","isPartOf":{"@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/"},"author":{"name":"Sebastian Meine","@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c"},"headline":"Merge Wonders \u2013 Insert or Use","datePublished":"2013-02-05T15:00:57+00:00","dateModified":"2014-11-13T18:48:15+00:00","mainEntityOfPage":{"@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/"},"wordCount":1431,"commentCount":0,"articleSection":["General","Hints","MERGE","Performance","T-SQL Statements"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/","url":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/","name":"Merge Wonders \u2013 Insert or Use - sqlity.net","isPartOf":{"@id":"https:\/\/sqlity.net\/en\/#website"},"datePublished":"2013-02-05T15:00:57+00:00","dateModified":"2014-11-13T18:48:15+00:00","author":{"@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c"},"description":"One of the most often encountered concurrency problems in T-SQL code happens in the Insert or Use scenario in which a new row is inserted if it does not exist yet and afterwards the primary key of the existing or the new row is returned. One of the easiest and safest ways to get this right is provided by the MERGE statement.","breadcrumb":{"@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/sqlity.net\/en\/1645\/merge-wonders-insert-or-use\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/sqlity.net\/en\/"},{"@type":"ListItem","position":2,"name":"Merge Wonders \u2013 Insert or Use"}]},{"@type":"WebSite","@id":"https:\/\/sqlity.net\/en\/#website","url":"https:\/\/sqlity.net\/en\/","name":"sqlity.net","description":"Quality for SQL","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/sqlity.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c","name":"Sebastian Meine","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","caption":"Sebastian Meine"},"sameAs":["http:\/\/sqlity.net","https:\/\/x.com\/sqlity"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2wXuw-qx","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts\/1645","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/comments?post=1645"}],"version-history":[{"count":0,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts\/1645\/revisions"}],"wp:attachment":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/media?parent=1645"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/categories?post=1645"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/tags?post=1645"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}