Home > Blockchain >  Updates and inserts by improving ON/GROUP By Clause
Updates and inserts by improving ON/GROUP By Clause

Time:09-22

Here is the sample of the Source and target table. I only have one unique id called "Premise_ID". I would like to update the target table based on Premise ID. When i am running below mentioned SQL query then I am getting an error mentioned below. I am having multiple rows with the same Premise_ID but with different column attributes.if the first Premise_ID matches then update all the column attributes. if the second Premise_ID is same as previous one then just add another row with all the column attributes. Is there any way to overcome this error?

Source Table

enter image description here

Target Table

enter image description here

SQL Query:

USE GIS_NewJersey
GO
WITH Source AS (
    SELECT Premise_ID, Division, InstallationType
    FROM sde.SAP_Load_test
),
Target AS (
    SELECT Premise_ID, Division, InstallationType
    FROM sde.PREMISE_test
)
MERGE Target t
USING Source s
  ON t.Premise_ID = s.Premise_ID
WHEN MATCHED THEN
  UPDATE SET
    Division = s.Division,
    InstallationType = s.InstallationType
WHEN NOT MATCHED THEN
  INSERT (Premise_ID, Division, InstallationType)
    VALUES (s.Premise_ID, s.Division, s.InstallationType)
;

ERROR:

The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.

CodePudding user response:

You can use 3 columns in MERGE SEARCH CONDITIONS and use WHEN NOT MATCHED BY TARGET to INSERT and WHEN NOT MATCHED BY SOURCE to DELETE

USE GIS_NewJersey
GO
WITH Source AS (
    SELECT Premise_ID, Division, InstallationType
    FROM sde.SAP_Load_test
),
Target AS (
    SELECT Premise_ID, Division, InstallationType
    FROM sde.PREMISE_test
)
MERGE Target t
USING Source s
  ON t.Premise_ID = s.Premise_ID
  AND t.Division = s.Division
  AND t.InstallationType = s.InstallationType
WHEN NOT MATCHED BY TARGET THEN
  INSERT (Premise_ID, Division, InstallationType)
    VALUES (s.Premise_ID, s.Division, s.InstallationType)
WHEN NOT MATCHED BY SOURCE THEN
  DELETE
;

CodePudding user response:

MERGE is problematic and unnecessarily complex for what is essentially a very basic "update if exists, otherwise insert" (or "UPSERT") problem. I have put together a page that links to several cautionary articles and alternative approaches:


Here's how I recommend you handle your logic, using separate and easier to troubleshoot update and insert commands (MERGE gives the illusion of being one operation, but it's not):

BEGIN TRANSACTION;
 
UPDATE pt WITH (UPDLOCK, SERIALIZABLE) 
  SET Division = s.Division, 
      InstallationType = s.InstallationType
  FROM sde.PREMISE_test AS pt
  INNER JOIN sde.SAP_Load_test AS s
    ON pt.Premise_ID = s.Premise_ID;

INSERT sde.PREMISE_test(Premise_ID, Division, InstallationType)
  SELECT s.Premise_ID, s.Division, s.InstallationType
    FROM sde.SAP_Load_test AS s
    WHERE NOT EXISTS (SELECT 1 FROM sde.PREMISE_test
      WHERE Premise_ID = s.Premise_ID);
 
COMMIT TRANSACTION;

But there's a problem, because it's unclear if you want to end up with multiple rows for any given Premise_ID in the target table (while you say one unique id called "Premise_ID", other things you're saying suggest you want multiple rows). In the fiddle, the row in the target for 8000004592 has been updated with an arbitrary row from the source (in reality, it was updated three times, this was just the "last" one - in some nondeterministic order). You also don't explain what you want to happen if there were two values for 8000004594 in the source - again, which row should it pick, if there is a unique constraint at the target? A table is an unordered bag of rows, so the concepts of "first" and "last" and "next" and "previous" don't make any sense unless you give it some deterministic meaning.


If you're going to ignore this advice and continue to use MERGE, even after reading (or not reading) all of the links, at the very least please put HOLDLOCK on the target.

  • Related