Skip to content

Instantly share code, notes, and snippets.

@danielrothfus
Created April 16, 2021 02:06
Show Gist options
  • Save danielrothfus/687736dafca82289e6558b0333bd52ee to your computer and use it in GitHub Desktop.
Save danielrothfus/687736dafca82289e6558b0333bd52ee to your computer and use it in GitHub Desktop.
-- Generate a vanilla MERGE statement for Microsoft SQL Server that performs an
-- upsert. You may need to further modify the generated statement to fit your
-- needs, but it should at least save you from typing the same fields in
-- quadruplicate.
--
-- History:
-- 2021-04-15: Daniel Rothfus - Initial version
DECLARE @MergeColumns TABLE([Name] SYSNAME NOT NULL);
INSERT INTO @MergeColumns
VALUES ('Key Column 1'), ('Key Column 2');
DECLARE @TargetTable SYSNAME = 'TargetTable';
DECLARE @Source NVARCHAR(MAX) = 'SourceTable';
DECLARE @Command NVARCHAR(MAX);
WITH AllColumns AS (
SELECT c.*
FROM sys.columns AS c
JOIN sys.objects AS o
ON c.object_id = o.object_id
WHERE o.name = @TargetTable
), AllQuotedColumnNames AS (
SELECT QUOTENAME([name]) AS [Name]
FROM AllColumns
), UpdateColumnNamesQuoted AS (
SELECT QUOTENAME([name]) AS [Name]
FROM AllColumns
WHERE [name] NOT IN (
SELECT [Name]
FROM @MergeColumns
)
)
SELECT @Command = CONCAT(
-- See https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/ for motivation behind HOLDLOCK
'MERGE INTO ', QUOTENAME(@TargetTable), ' WITH (HOLDLOCK) AS t ', CHAR(10),
'USING ', QUOTENAME(@Source), ' AS s', CHAR(10),
'ON ', (
SELECT STRING_AGG(CONCAT('t.', QUOTENAME([Name]), ' = s.', QUOTENAME([Name])), CONCAT(CHAR(10), ' AND '))
FROM @MergeColumns
), CHAR(10),
'WHEN MATCHED THEN UPDATE SET ', (
SELECT STRING_AGG(CONCAT('t.', [Name], ' = s.', [Name]), CONCAT(',', CHAR(10), ' '))
FROM UpdateColumnNamesQuoted
), CHAR(10),
'WHEN NOT MATCHED THEN INSERT (', CHAR(10),
(
SELECT STRING_AGG(CONCAT(' ', [Name]), CONCAT(', ', CHAR(10)))
FROM AllQuotedColumnNames
), CHAR(10),
') VALUES (', CHAR(10),
(
SELECT STRING_AGG(CONCAT(' s.', [Name]), CONCAT(', ', CHAR(10)))
FROM AllQuotedColumnNames
), CHAR(10),
')'
)
PRINT(@Command);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment