MERGE Query and deleting records

前端 未结 4 1583
花落未央
花落未央 2021-01-01 09:02

I have a table that looks something like:

AccountID, ItemID
1, 100
1, 200
2, 300

I have a proc that accepts a table value parameter which u

相关标签:
4条回答
  • 2021-01-01 09:41

    The above answer works in the situation that is described.

    I have an exception table that I use to store exceptions to invoices. I only want it to contain the current exceptions for the invoice. So, if I fix some of things in the invoice data and run the process again it will create a new list of exceptions. I want it to add the new exceptions, update existing ones, and delete the exceptions that no longer exist - SO LONG AS THEY BELONG TO THE SAME INVOICE (or whatever).

    The problem I had was that the MERGE statement WHEN NOT MATCHED BY SOURCE THEN DELETE would delete everything in the TARGET table; not just the extra items no longer in the SOURCE! I could not qualify the WHEN NOT MATCHED BY SOURCE statement so that the DELETE would only affect the same invoice number in the TARGET that was no longer in the SOURCE.

    An error told me "Only target columns are allowed in the 'WHEN NOT MATCHED BY SOURCE' clause of a MERGE statement."

    So you have to qualify the TARGET rows with a variable.

    0 讨论(0)
  • 2021-01-01 09:47

    Hope this helps.

    --  myTable
    --  (
    --      GroundID bigint, -- FK
    --      GroupID, bigint, -- FK
    --      AcceptingReservations bit
    --  );
    
    merge into myTable as target
    using @tmpTable as source
        on  ( source.GroundID   = target.GroundID )
        and ( source.GroupID    = target.GroupID )
    when
        not matched by target
        then
            insert ( GroundID, GroupID, AcceptingReservations )
            values
            (
                source.GroundID,
                source.GroupID,
                source.AcceptingReservations
            )
    -- If there is a row that matches, update values;
    when matched
        then
            update set
                target.AcceptingReservations = source.AcceptingReservations
    -- If they do not match, delete for that GroundID only;
    when
        not matched by source
        and target.GroundID = @GroundID
            then
                delete;
    
    0 讨论(0)
  • 2021-01-01 09:54

    Create a table type variable in sql database

    CREATE TYPE [dbo].[YourTableType] AS TABLE(
         [AccountID] [int] NULL,
         [ItemID] [int] NULL
         )
       GO
    

    Make Changes in your Update Procedure

    ALTER PROCEDURE YourProcedure
    @Items YourTableType READONLY
    AS
    BEGIN
       MERGE INTO [dbo].[YourTable] as Target
       USING @Items as Source
    ON 
        Target.[AccountID]=Source.[AccountID] and 
        Target.[ItemID]=Source.[ItemID] 
       WHEN NOT MATCHED by TARGET THEN
         INSERT 
            ([AccountID],
             [ItemID])
         VALUES 
           (Source.[AccountID],
            Source.[ItemID])
    
       WHEN NOT MATCHED BY SOURCE AND 
            target.[ItemID] IN(SELECT [ItemID] FROM @Items) 
    THEN
        DELETE;
    

    END

    0 讨论(0)
  • 2021-01-01 09:57

    I can think of two obvious ways but both of them involve processing the TVP again.

    The first is simply to change the DELETE condition

        WHEN NOT MATCHED BY SOURCE 
        AND target.AccountId IN(SELECT AccountId FROM @Items) THEN
            DELETE;
    

    The second is to use a CTE to restrict the target

    WITH cte as
    (
    SELECT ItemId, AccountId 
    FROM @myTable m
    WHERE EXISTS 
      (SELECT * FROM @Items i WHERE i.AccountId = m.AccountId)
    )
          MERGE INTO cte as target
            USING @Items Items
               ON (Items.AccountId = target.AccountId) AND
                  (Items.ItemId = target.ItemId)
            WHEN NOT MATCHED BY TARGET THEN
                INSERT (AccountId, ItemId)
                VALUES (Items.AccountId, Items.ItemId)
             WHEN NOT MATCHED BY SOURCE THEN 
                DELETE;
    
    0 讨论(0)
提交回复
热议问题