MERGE Запрос и удаление записей - PullRequest
26 голосов
/ 04 марта 2011

У меня есть таблица, которая выглядит примерно так:

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

У меня есть процесс, который принимает параметр табличного значения, который обновляет элементы, связанные с учетной записью. Мы передадим что-то вроде следующего:

AccountID, ItemID
3, 100
3, 200

Процесс выглядит примерно так:

procedure dbo.MyProc( @Items as dbo.ItemListTVP READONLY )
AS
BEGIN
  MERGE INTO myTable as target
    USING @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)

   ;

END

На основании переданных данных я ожидаю, что он добавит 2 новые записи в таблицу, что он и делает.

Я хочу иметь предложение WHEN NOT MATCHED BY SOURCE, которое удалит элементы для указанной учетной записи , которые не совпадают.

Например, если я пройду

AccountID, ItemID
1, 100
1, 400

Тогда я хочу удалить запись, имеющую 1, 200; но оставь ВСЕХ остальных.

Если я просто сделаю:

WHEN NOT MATCHED BY SOURCE THEN
  DELETE;

тогда он удалит все записи для учетных записей, на которые нет ссылок (т. Е. Идентификаторы учетных записей 2 и 3).

Как я могу это сделать?

Спасибо

Ответы [ 4 ]

41 голосов
/ 04 марта 2011

Я могу придумать два очевидных способа, но оба они снова включают обработку TVP.

Первое - просто изменить условие DELETE

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

Второй - использовать CTE для ограничения цели

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;
5 голосов
/ 30 декабря 2013

Надеюсь, это поможет.

--  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;
2 голосов
/ 13 февраля 2017

Создать переменную табличного типа в базе данных sql

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

Внести изменения в процедуру обновления

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 голосов
/ 11 февраля 2014

Ответ выше работает в описанной ситуации.

У меня есть таблица исключений, которую я использую для хранения исключений в счетах.Я только хочу, чтобы он содержал текущие исключения для счета.Поэтому, если я исправлю некоторые данные в данных счета и снова запустю процесс, он создаст новый список исключений.Я хочу, чтобы он добавил новые исключения, обновил существующие и удалил исключения, которых больше не существует - ТАК ДЛИННО, ЧТО ОНИ ПРИНАДЛЕЖАЛИ ОДНОВРЕМЕННОМУ СЧЕТУ (или какому-то другому).

Проблема, с которой я столкнулся, заключалась в том, что MERGEоператор, КОГДА НЕ СОГЛАСОВАННЫЙ ИСТОЧНИКОМ, ПОТОМ УДАЛИТ, удалит все в таблице TARGETне просто лишних предметов больше нет в ИСТОЧНИКЕ!Я не смог определить оператор WHEN NOT MATCHED BY SOURCE, чтобы DELETE влиял только на тот же номер счета-фактуры в TARGET, которого больше не было в SOURCE.

Ошибка сообщала мне: «В предложении« WHEN NOT MATCHED BY SOURCE »инструкции MERGE разрешены только целевые столбцы».

Поэтому необходимо квалифицировать строки TARGET с помощью переменной.

...