Reputation: 4800
I wish to use a single SQL statement (i.e., "MERGE") to manage a table representing a mathematical set: insert element if true, else remove.
Using ice cream as an example, I want to add a flavor or remove a flavor from the list based on the @Exist flag below. Is this possible? I've played with it for several hours and either it is syntatically correct and doesn't INSERT the row or I write the query to do what I think needs to be done but then won't compile because the syntax isn't valid. (MSDN MERGE "man" page)
Here is my feable attempt:
CREATE TABLE IceCream(
Flavor VARCHAR(50) NOT NULL,
CONSTRAINT AK_Flavor UNIQUE(Flavor)
)
DECLARE @Flavor varchar(50)
DECLARE @Exist bit
set @Flavor='Vanilla'
set @Exist=1
MERGE IceCream AS T
USING IceCream AS S
ON S.Flavor=T.Flavor AND
S.Flavor=@Flavor AND
T.Flavor=@Flavor
WHEN NOT MATCHED BY TARGET AND @Exist=1
THEN INSERT (Flavor) VALUES (@Flavor)
WHEN NOT MATCHED BY SOURCE AND @Exist=0
THEN DELETE
OUTPUT $action, inserted.*, deleted.*;
Upvotes: 0
Views: 725
Reputation: 3540
Although there are different ways of accomplishing your goal, this MERGE
statement will work:
DECLARE @Flavor varchar(50), @Exist bit;
SET @Flavor = 'Orange';
SET @Exist = 1;
;WITH TGT AS (SELECT Flavor FROM IceCream WHERE Flavor = @Flavor)
MERGE INTO TGT
USING (VALUES(@Flavor, @Exist)) AS SRC(Flavor, Exist)
ON TGT.Flavor = SRC.Flavor
WHEN MATCHED AND SRC.Exist = 0
THEN DELETE
WHEN NOT MATCHED BY TARGET AND SRC.Exist = 1
THEN INSERT (Flavor) VALUES (SRC.Flavor);
Start with an initial list:
INSERT INTO IceCream VALUES ('Vanilla'), ('Chocolate'), ('Strawberry')
And testing with a few different pairs (Flavor, Exist):
[Orange,1]
----------
Chocolate, Orange, Strawberry, Vanilla
[Rasberry,0]
----------
Chocolate, Orange, Strawberry, Vanilla
[Vanilla,0]
----------
Chocolate, Orange, Strawberry
[Chocolate,1]
----------
Chocolate, Orange, Strawberry
[Java,1]
----------
Chocolate, Java, Orange, Strawberry
Simplification:
Actually, I used the CTE as the target because your original example had the WHEN NOT MATCHED BY SOURCE THEN DELETE
and nine times out of ten, when synchonizing a set, your target needs to be constrained by a subquery (a CTE in the case of MERGE).
However, your actual needs do not seem to require a WHEN NOT MATCHED BY SOURCE
clause, and therefore you can simplify the above statement, with the same results:
;MERGE INTO IceCream AS TGT
USING (VALUES(@Flavor, @Exist)) AS SRC(Flavor, Exist)
ON TGT.Flavor = SRC.Flavor
WHEN MATCHED AND SRC.Exist = 0
THEN DELETE
WHEN NOT MATCHED BY TARGET AND SRC.Exist = 1
THEN INSERT (Flavor) VALUES (SRC.Flavor);
Upvotes: 1