Basically I have a SQL Server 2008 R2 database. The database has a table called Node and Link. Link contains a StartNodeId and EndNodeId relating to a Id in Node. The database also requires a Link table between Node and Link for quicker checking of say, is this Node related to this Link or which Nodes are related to this Link. The Link table contains a Identity key, NodeId and LinkId. My problem is when I am doing my inserts I am trying to use merge statements which do not seem to be able to do what I am trying
When I tried
MERGE INTO [RoadRoutingDatabase].[dbo].[NodeToLink] AS TARGET
USING (SELECT Id, StartNodeId, EndNodeId FROM [RoadRoutingDatabase].[dbo].[Link]) AS SOURCE
ON (TARGET.LinkId = SOURCE.Id)
WHEN MATCHED AND TARGET.NodeId = Source.StartNodeId THEN
UPDATE SET TARGET.NodeId = SOURCE.StartNodeId,
TARGET.LinkId = SOURCE.Id
WHEN MATCHED AND TARGET.NodeId = Source.EndNodeId THEN
UPDATE SET TARGET.NodeId = SOURCE.EndNodeId,
TARGET.LinkId = SOURCE.Id
WHEN NOT MATCHED BY TARGET AND TARGET.NodeId = Source.StartNodeId THEN
INSERT (LinkId, NodeId)
VALUES (SOURCE.Id, SOURCE.StartNodeId)
WHEN NOT MATCHED BY TARGET AND TARGET.NodeId = Source.EndNodeId THEN
INSERT (LinkId, NodeId)
VALUES (SOURCE.Id, SOURCE.EndNodeId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
I get the error message "An action of type 'WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement"
If I try inserting Start Nodes and End Nodes seperatly e.g.
--Insert Start Node To Link Relationships
MERGE INTO [RoadRoutingDatabase].[dbo].[NodeToLink] AS TARGET
USING (SELECT Id, StartNodeId FROM [RoadRoutingDatabase].[dbo].[Link]) AS SOURCE
ON (TARGET.NodeId = SOURCE.StartNodeId AND TARGET.LinkId = SOURCE.Id)
WHEN MATCHED THEN
UPDATE SET TARGET.NodeId = SOURCE.StartNodeId,
TARGET.LinkId = SOURCE.Id
WHEN NOT MATCHED BY TARGET THEN
INSERT (LinkId, NodeId)
VALUES (SOURCE.Id, SOURCE.StartNodeId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
--Insert End Node To Link Relationships
MERGE INTO [RoadRoutingDatabase].[dbo].[NodeToLink] AS TARGET
USING (SELECT Id, EndNodeId FROM [RoadRoutingDatabase].[dbo].[Link]) AS SOURCE
ON (TARGET.NodeId = SOURCE.EndNodeId AND TARGET.LinkId = SOURCE.Id)
WHEN MATCHED THEN
UPDATE SET TARGET.NodeId = SOURCE.EndNodeId,
TARGET.LinkId = SOURCE.Id
WHEN NOT MATCHED BY TARGET THEN
INSERT (LinkId, NodeId)
VALUES (SOURCE.Id, SOURCE.EndNodeId)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
I end up with links being deleted (not surprising) so basically I was wondering if anyone knew of a good way of doing this? If possible I would like to be able to do it still using a merge statement
Thanks
Edit: I have found a different way of merging this data using a different source, the problem is now solved.
Answer. Testing with a variety of source row sets against a target with about 6 mio. rows showed a slighty time advance using the merge command. Overall less internal steps are performed in the merge compared to delete/insert.
The MERGE statement tries to compare the source table with the target table based on a key field and then do some of the processing. The MERGE statement actually combines the INSERT, UPDATE, and the DELETE operations altogether.
MERGE is designed to apply both UPDATE and INSERTs into a target table from a source table. The statement can do both at once, or simply do INSERTs or only UPDATEs. One might even get the impression that INSERT and UPDATE are no longer needed.
Try this approach: MERGE [Table1] AS Target USING [Table2] AS Source ON Target.Name = Source.Name WHEN MATCHED THEN UPDATE SET Target.
Maybe I'm missing something but
The error message complains you can't have multiple WHEN MATCHED
so you could convert
WHEN MATCHED AND TARGET.NodeId = Source.StartNodeId THEN
UPDATE SET TARGET.NodeId = SOURCE.StartNodeId,
TARGET.LinkId = SOURCE.Id
WHEN MATCHED AND TARGET.NodeId = Source.EndNodeId THEN
UPDATE SET TARGET.NodeId = SOURCE.EndNodeId,
TARGET.LinkId = SOURCE.Id
to
WHEN MATCHED AND TARGET.NodeId IN (Source.StartNodeId,Source.EndNodeId) THEN
UPDATE SET TARGET.NodeId = CASE
WHEN TARGET.NodeId = Source.StartNodeId
THEN SOURCE.StartNodeId
ELSE Source.EndNodeId
END,
TARGET.LinkId = SOURCE.Id
But as the first branch of the CASE
is hit when TARGET.NodeId = Source.StartNodeId
and also sets TARGET.NodeId = Source.StartNodeId
and similarly for the second branch then that seems to simplify to
WHEN MATCHED AND TARGET.NodeId IN (Source.StartNodeId,Source.EndNodeId) THEN
UPDATE SET TARGET.LinkId = SOURCE.Id
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With