You need a MERGE
in order to do both inserts and updates. You can use a VALUES
virtual table as the source, or another table or table variable.
MERGE dbo.table1 AS t WITH (HOLDLOCK)
USING (VALUES
('SomePK', 'value1', 'value2', 'value1')
) s(PK, column1, column2, column3)
ON s.PK = t.PK -- do not put any other conditions here
WHEN NOT MATCHED THEN
INSERT (column1, column2, column3)
VALUES (s.column1, s.column2, s.column3)
WHEN MATCHED AND EXISTS (
SELECT s.column1, s.column2, s.column3
EXCEPT
SELECT t.column1, t.column2, t.column3
) THEN UPDATE SET
column1 = s.column1,
column2 = s.column2,
column3 = s.column3
;
The EXCEPT
syntax is only necessary if you have nullable columns. Otherwise you can just do normal <>
conditions.
You can also just use an INSERT
UPDATE
combination, along with a transaction and the correct locking hints
SET XACT_ABORT, NOCOUNT ON;
BEGIN TRAN;
INSERT INTO dbo.table1 (PK, column1, column2, column3)
SELECT 'SomePK', 'value1', 'value2', 'value1'
WHERE NOT EXISTS (SELECT 1
FROM dbo.table1 t1 WITH (HOLDLOCK, UPDLOCK)
WHERE t1.PK = 'SomePK'
);
IF @@ROWCOUNT = 0
UPDATE dbo.table1 WITH (HOLDLOCK, UPDLOCK)
SET column1 = 'value1',
column2 = 'value2',
column3 = 'value1'
WHERE PK = 'SomePK'
AND EXISTS (
SELECT 'value1', 'value2', 'value1'
EXCEPT
SELECT t.column1, t.column2, t.column3
);
COMMIT;
You can swap around the INSERT
and UPDATE
if you think the latter is more likely than the former.
See also this article for further information.