Поделиться через


MERGE (Transact-SQL)

Выполняет операции вставки, обновления или удаления для целевой таблицы на основе результатов соединения с исходной таблицей. Например, можно синхронизировать две таблицы путем вставки, обновления или удаления строк в одной таблице на основании отличий, найденных в другой таблице.

Значок ссылки на разделСинтаксические обозначения в Transact-SQL

Синтаксис

[ WITH <common_table_expression> [,...n] ]
MERGE 
        [ TOP ( expression ) [ PERCENT ] ] 
        [ INTO ] <target_table> [ WITH ( <merge_hint> ) ] [ [ AS ] table_alias ]
        USING <table_source> 
        ON <merge_search_condition>
        [ WHEN MATCHED [ AND <clause_search_condition> ]
            THEN <merge_matched> ] [...n ]
        [ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]
            THEN <merge_not_matched> ]
        [ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]
            THEN <merge_matched> ] [...n ]
        [ <output_clause> ]
        [ OPTION ( <query_hint> [ ,...n ] ) ]    
;

<target_table> ::=
{ 
    [ database_name . schema_name . | schema_name . ]
    target_table
}

<merge_hint>::=
{
    { [ <table_hint_limited> [ ,...n ] ]
    [ [ , ] INDEX ( index_val [ ,...n ] ) ] }
}

<table_source> ::= 
{
        table_or_view_name [ [ AS ] table_alias ] [ <tablesample_clause> ] 
            [ WITH ( table_hint [ [ , ]...n ] ) ] 
    | rowset_function [ [ AS ] table_alias ] 
            [ ( bulk_column_alias [ ,...n ] ) ] 
    | user_defined_function [ [ AS ] table_alias ]
    | OPENXML <openxml_clause> 
    | derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ] 
    | <joined_table> 
    | <pivoted_table> 
    | <unpivoted_table> 
}

<merge_search_condition> ::=
    <search_condition>

<merge_matched>::=
    { UPDATE SET <set_clause> | DELETE }

<set_clause>::=
SET
    { column_name = { expression | DEFAULT | NULL }
  | { udt_column_name.{ { property_name = expression
                                              | field_name = expression }
                                              | method_name ( argument [ ,...n ] ) }
     }
  | column_name { .WRITE ( expression , @Offset , @Length ) }
  | @variable = expression
  | @variable = column = expression
  | column_name { += | -= | *= | /= | %= | &= | ^= | |= } expression
  | @variable { += | -= | *= | /= | %= | &= | ^= | |= } expression
  | @variable = column { += | -= | *= | /= | %= | &= | ^= | |= } expression
  } [ ,...n ] 

<merge_not_matched>::=
{
        INSERT [ ( column_list ) ] 
            { VALUES ( values_list )
            | DEFAULT VALUES }
}

<clause_search_condition> ::=
    <search_condition>

<search condition> ::=
        { [ NOT ] <predicate> | ( <search_condition> ) } 
        [ { AND | OR } [ NOT ] { <predicate> | ( <search_condition> ) } ] 
[ ,...n ] 

<predicate> ::= 
    { expression { = | < > | ! = | > | > = | ! > | < | < = | ! < } expression 
    | string_expression [ NOT ] LIKE string_expression 
  [ ESCAPE 'escape_character' ] 
    | expression [ NOT ] BETWEEN expression AND expression 
    | expression IS [ NOT ] NULL 
    | CONTAINS 
    ( { column | * } , '< contains_search_condition >' ) 
    | FREETEXT ( { column | * } , 'freetext_string' ) 
    | expression [ NOT ] IN ( subquery | expression [ ,...n ] ) 
    | expression { = | < > | ! = | > | > = | ! > | < | < = | ! < } 
  { ALL | SOME | ANY} ( subquery ) 
    | EXISTS ( subquery ) } 

<output_clause>::=
{
        [ OUTPUT <dml_select_list> INTO { @table_variable | output_table }
            [ (column_list) ] ]
    [ OUTPUT <dml_select_list> ]
}

<dml_select_list>::=
        { <column_name> | scalar_expression } 
                [ [AS] column_alias_identifier ] [ ,...n ]

<column_name> ::=
        { DELETED | INSERTED | from_table_name } . { * | column_name }
      | $action

Аргументы

  • WITH <common_table_expression>
    Указывает определенные в области инструкции MERGE временные именованные результирующие набор или представление, которые называются обобщенным табличным выражением. Результирующий набор, на который ссылается инструкция MERGE, является производным простого запроса. Дополнительные сведения см. в разделе WITH обобщенное_табличное_выражение (Transact-SQL).

  • TOP ( expression ) [ PERCENT ]
    Указывает количество или процент строк, которые подпадают под эту операцию. expression может быть либо числом, либо процентной долей строк. Строки, на которые ссылается выражение TOP, не расположены в определенном порядке. Дополнительные сведения см. в разделе TOP (Transact-SQL).

    Предложение TOP применяется после соединения всей исходной таблицы и всей целевой таблицы и удаления соединенных строк, которые не рассматриваются как предназначенные для выполнения операций вставки, обновления или удаления. Предложение TOP дополнительно сокращает количество соединенных строк до указанного значения, а затем к оставшимся соединенным строкам применяются операции вставки, обновления или удаления без учета порядка. Иными словами, порядок, в котором строки подвергаются операциям, определенным в предложениях WHEN, не задан. Например, указание значения TOP (10) затрагивает 10 строк. Из них 7 могут быть обновлены и 3 вставлены или одна строка может быть удалена, 5 обновлено, 4 вставлено и т. д.

    Инструкция MERGE выполняет полный просмотр исходной и целевой таблиц, поэтому при использовании предложения TOP для изменения большой таблицы путем создания нескольких пакетов производительность ввода-вывода может снизиться. В этом случае необходимо обеспечить, чтобы во всех подряд идущих пакетах осуществлялась обработка новых строк. Дополнительные сведения см. в разделе Оптимизация производительности инструкции MERGE.

  • database_name
    Имя базы данных, в которой расположена таблица target_table.

  • schema_name
    Имя схемы, которой принадлежит таблица target_table.

  • target_table
    Таблица или представление, с которыми выполняется сопоставление строк данных из таблицы <table_source> по условию <clause_search_condition>. Параметр target_table является целевым объектом любых операций вставки, обновления или удаления, указанных предложениями WHEN инструкции MERGE.

    Если аргумент target_table является представлением, то все действия, выполняемые с ним, должны удовлетворять условиям для обновления представлений. Дополнительные сведения см. в разделе Изменение данных через представление.

    Таблица target_table не может быть удаленной, и для нее не могут быть определены правила.

  • [AS] table_alias
    Альтернативное имя, используемое для указания ссылок на эту таблицу.

  • USING <table_source>
    Указывается источник данных, который сопоставляется со строками данных в таблице target_table на основе условия <merge_search condition>. Результат этого совпадения обуславливает действия, которые выполняются предложениями WHEN инструкции MERGE. Аргумент <table_source> может быть удаленной таблицей или производной таблицей, которая обращается к удаленным таблицам.

    Аргументом <table_source> может быть производная таблица, использующая конструктор табличных значенийTransact-SQL для построения таблицы путем указания нескольких строк.

    Дополнительные сведения о синтаксисе и аргументах этого предложения см. в разделе Предложение FROM (Transact-SQL).

  • ON <merge_search_condition>
    Указываются условия, при которых таблица <table_source> соединяется с таблицей target_table для сопоставления.

    ПредупреждениеВнимание!

    Важно указать только те столбцы из целевой таблицы, которые используются для поиска совпадений. Иными словами, необходимо указать столбцы целевой таблицы, которые сравниваются с соответствующим столбцом исходной таблицы. Не рекомендуется повышать производительность запроса за счет фильтрации строк в целевой таблице в предложении ON, как например, при указании AND NOT target_table.column_x = value. Это может привести к получению непредвиденных и неверных результатов.

  • WHEN MATCHED THEN <merge_matched>
    Указывается, что все строки target_table, которые соответствуют строкам, возвращенным <table_source> ON <merge_search_condition>, и удовлетворяют дополнительным условиям поиска, обновляются или удаляются в соответствии с предложением <merge_matched>.

    Инструкция MERGE может иметь не больше двух предложений WHEN MATCHED. Если указаны два предложения, первое предложение должно сопровождаться предложением AND <search_condition>. Для любой строки второе предложение WHEN MATCHED применяется только в тех случаях, когда не применяется первое. Если имеются два предложения WHEN MATCHED, одно должно указывать действие UPDATE, а другое — действие DELETE. Если действие UPDATE указано в предложении <merge_matched> и более одной строки в <table_source>соответствует строке в target_table на основе <merge_search_condition>, то SQL Server возвращает ошибку. Инструкцию MERGE нельзя использовать для обновления одной строки более одного раза, а также использовать для обновления и удаления одной и той же строки.

  • WHEN NOT MATCHED [ BY TARGET ] THEN <merge_not_matched>
    Указывает, что строка вставлена в таблицу target_table для каждой строки, возвращенной выражением <table_source> ON <merge_search_condition>, которые не соответствуют строке в таблице target_table, но удовлетворяют дополнительному условию поиска (при наличии такового). Значения для вставки указываются с помощью предложения <merge_not_matched>. Инструкция MERGE может иметь только одно предложение WHEN MATCHED.

  • WHEN NOT MATCHED BY SOURCE THEN <merge_matched>
    Указывается, что все строки target_table, которые не соответствуют строкам, возвращенным <table_source> ON <merge_search_condition>, и удовлетворяют дополнительным условиям поиска, обновляются или удаляются в соответствии с предложением <merge_matched>.

    Инструкция MERGE может иметь не более двух предложений WHEN NOT MATCHED BY SOURCE. Если указаны два предложения, то первое предложение должно сопровождаться предложением AND <clause_search_condition>. Для любой выбранной строки второе предложение WHEN NOT MATCHED BY SOURCE применяется только в тех случаях, если не применяется первое. Если имеется два предложения WHEN NOT MATCHED BY SOURCE, то одно должно указывать действие UPDATE, а другое — действие DELETE. В условии <clause_search_condition> можно ссылаться только на столбцы целевой таблицы.

    Если строки не возвращаются таблицей <table_source>, к столбцам в исходной таблице не может быть предоставлен доступ. Если операции обновления или удаления указываются в <merge_matched>, предложение ссылается на исходную таблицу и возвращается ошибка 207 (недопустимое имя столбца). Например, предложение WHEN NOT MATCHED BY SOURCE THEN UPDATE SET TargetTable.Col1 = SourceTable.Col1 может стать причиной ошибки инструкции из-за недоступности столбца Col1 в исходной таблице.

  • AND <clause_search_condition>
    Указывается любое действительное условие поиска. Дополнительные сведения см. в разделе Условие поиска (Transact-SQL).

  • <table_hint_limited>
    Указывается одна или несколько табличных подсказок, которые применяются в целевой таблице для каждой операции вставки, обновления или удаления, которые выполняются инструкцией MERGE. Необходимо использовать ключевое слово WITH и круглые скобки.

    Использование аргументов NOLOCK и READUNCOMMITTED запрещено. Дополнительные сведения о табличных подсказках см. в разделе Табличные подсказки (Transact-SQL).

    Указание подсказки TABLOCK для целевой таблицы инструкции INSERT приведет к тем же последствиям, что и указание подсказки TABLOCKX. К таблице будет применена монопольная блокировка. Если указано FORCESEEK, то оно применяется к явному экземпляру целевой таблицы, соединенной с исходной таблицей.

    ПредупреждениеВнимание!

    Указание READPAST с предложением WHEN NOT MATCHED [ BY TARGET ] THEN INSERT может привести к выполнению операций INSERT, которые нарушают ограничения UNIQUE.

  • INDEX ( index_val [ ,...n ] )
    Указывается имя или идентификатор одного или нескольких индексов целевой таблицы для выполнения явного соединения с исходной таблицей. Дополнительные сведения см. в разделе Табличные подсказки (Transact-SQL).

  • <output_clause>
    Возвращает строку для каждой строки в target_table, которая обновляется, вставляется или удаляется без определенного порядка. Дополнительные сведения об аргументах этого предложения см. в разделе Предложение OUTPUT (Transact-SQL).

  • OPTION ( <query_hint> [ ,...n ] )
    Указывает, что для настройки способа, которым компонент Database Engine обрабатывает инструкцию, используются подсказки оптимизатора. Дополнительные сведения см. в разделе Подсказки в запросах (Transact-SQL).

  • <merge_matched>
    Указывает действие обновления или удаления, которое применяется ко всем строкам target_table, не соответствующим строкам, которые возвращаются <table_source> ON <merge_search_condition> и удовлетворяют каким-либо дополнительным условиям поиска.

    • UPDATE SET <set_clause>
      Указывается список имен столбцов или переменных, которые необходимо обновить в целевой таблице, и значений, которые необходимо использовать для их обновления.

      Дополнительные сведения об аргументах этого предложения см. в разделе UPDATE (Transact-SQL). Присваивание переменной того же значения, что и столбцу, не разрешается.

    • DELETE
      Указывается, что строки, совпадающие со строками в target_table, удаляются.

  • <merge_not_matched>
    Указываются значения для вставки в целевую таблицу.

    • ( column_list )
      Список, состоящий из одного или нескольких столбцов целевой таблицы, в которые вставляются данные. Столбцы необходимо указывать в виде однокомпонентного имени, так как в противном случае инструкция MERGE возвращает ошибку. Аргумент column_list должен быть заключен в скобки и разделен запятыми.

    • VALUES ( values_list )
      Список с разделителями-запятыми ограничений, переменных или выражений, которые возвращают значения для вставки в целевую таблицу. Выражения не могут содержать инструкцию EXECUTE.

    • DEFAULT VALUES
      Заполняет вставленную строку значениями по умолчанию, определенными для каждого столбца.

    Дополнительные сведения об этом предложении см. в разделе Инструкция INSERT (Transact-SQL).

  • <search condition>
    Указываются условия поиска, используемые для указания <merge_search_condition> или <clause_search_condition>. Дополнительные сведения об аргументах этого предложения см. в разделе Условие поиска (Transact-SQL).

Замечания

Должно быть указано по крайней мере одно из трех предложений MATCHED, но они могут быть указаны в любом порядке. В одном предложении MATCHED переменная не может быть обновлена больше одного раза.

На все операции удаления, вставки или обновления, указанные применительно к целевой таблице инструкции MERGE, распространяются все ограничения, определенные для этой таблицы, включая все каскадные ограничения ссылочной целостности. Если IGNORE_DUP_KEY имеет значение ON для всех уникальных индексов в целевой таблице, то в инструкции MERGE этот параметр не учитывается.

Чтобы использовать инструкцию MERGE, необходима точка с запятой (;) как признак конца инструкции. Возникает ошибка 10713, если инструкция MERGE выполняется без признака конца конструкции.

Если функция @@ROWCOUNT (Transact-SQL) используется после инструкции MERGE, она возвращает общее количество вставленных, обновленных и удаленных строк из клиента.

Ключевое слово MERGE полностью резервируется, если уровень совместимости базы данных установлен в значение 100. Инструкция MERGE доступна при уровне совместимости базы данных 90 и 100, однако это ключевое слово не полностью зарезервировано при уровне совместимости 90.

Реализация триггера

Для каждой операции вставки, обновления или удаления, указанной в инструкции MERGE, SQL Server запускает все соответствующие триггеры AFTER, определенные для целевой таблицы, но не гарантирует определенного порядка запуска триггеров. Триггеры, которые определены для одного и того же действия, реализуются в порядке, указанном пользователем. Дополнительные сведения о настройке порядка выполнения триггеров см. в разделе Указание первого и последнего триггеров.

Если в целевой таблице включен триггер INSTEAD OF для операций вставки, обновления или удаления, выполняемых инструкцией MERGE, то должен быть включен триггер INSTEAD OF для всех операций, указанных в инструкции MERGE.

Если в таблице target_table определены триггеры INSTEAD OF UPDATE или INSTEAD OF DELETE, то операции обновления или удаления не выполняются. Вместо этого запускаются триггеры, а таблицы inserted и deleted заполняются соответствующим образом.

Если в таблице target_table определены триггеры INSTEAD OF INSERT, то операции вставки не выполняются. Вместо этого запускаются триггеры, и таблица inserted заполняется соответствующим образом.

Разрешения

Необходимо разрешение SELECT для исходной таблицы и разрешения INSERT, UPDATE или DELETE для целевой таблицы. Дополнительные сведения см. в подразделах SELECT, INSERT, UPDATE и DELETE раздела «Разрешения».

Примеры

А. Использование инструкции MERGE для выполнения операций INSERT и UPDATE в таблице в одной инструкции

Чаще всего производится обновление одного или нескольких столбцов в таблице, если существуют совпадающие строки, либо вставка данных в новую строку, если совпадающих строк не существует. Это обычно выполняется путем передачи параметров хранимой процедуре, содержащей подходящие инструкции UPDATE и INSERT. Используя инструкцию MERGE, обе эти задачи можно реализовать в одной инструкции. В следующем примере показывается хранимая процедура, содержащая инструкции INSERT и UPDATE. Затем процедура изменяется для выполнения эквивалентных операций с использованием единственной инструкции MERGE.

USE AdventureWorks;
GO
CREATE PROCEDURE dbo.InsertUnitMeasure
    @UnitMeasureCode nchar(3),
    @Name nvarchar(25)
AS 
BEGIN
    SET NOCOUNT ON;
-- Update the row if it exists.    
    UPDATE Production.UnitMeasure
    SET Name = @Name
    WHERE UnitMeasureCode = @UnitMeasureCode
-- Insert the row if the UPDATE statement failed.   
    IF (@@ROWCOUNT = 0 )
    BEGIN
        INSERT INTO Production.UnitMeasure (UnitMeasureCode, Name)
        VALUES (@UnitMeasureCode, @Name)
    END
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Test Value';
SELECT UnitMeasureCode, Name FROM Production.UnitMeasure
WHERE UnitMeasureCode = 'ABC';
GO

-- Rewrite the procedure to perform the same operations using the MERGE statement.
-- Create a temporary table to hold the updated or inserted values from the OUTPUT clause.
CREATE TABLE #MyTempTable
    (ExistingCode nchar(3),
     ExistingName nvarchar(50),
     ExistingDate datetime,
     ActionTaken nvarchar(10),
     NewCode nchar(3),
     NewName nvarchar(50),
     NewDate datetime
    );
GO
ALTER PROCEDURE dbo.InsertUnitMeasure
    @UnitMeasureCode nchar(3),
    @Name nvarchar(25)
AS 
BEGIN
    SET NOCOUNT ON;

    MERGE Production.UnitMeasure AS target
    USING (SELECT @UnitMeasureCode, @Name) AS source (UnitMeasureCode, Name)
    ON (target.UnitMeasureCode = source.UnitMeasureCode)
    WHEN MATCHED THEN 
        UPDATE SET Name = source.Name
    WHEN NOT MATCHED THEN   
        INSERT (UnitMeasureCode, Name)
        VALUES (source.UnitMeasureCode, source.Name)
        OUTPUT deleted.*, $action, inserted.* INTO #MyTempTable;
END;
GO
-- Test the procedure and return the results.
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'New Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'XYZ', @Name = 'Test Value';
EXEC InsertUnitMeasure @UnitMeasureCode = 'ABC', @Name = 'Another Test Value';

SELECT * FROM #MyTempTable;
-- Cleanup 
DELETE FROM Production.UnitMeasure WHERE UnitMeasureCode IN ('ABC','XYZ');
DROP TABLE #MyTempTable;
Go

Б. Использование инструкции MERGE для выполнения операций UPDATE и DELETE в таблице в одной инструкции

В следующем примере инструкция MERGE используется для ежедневного обновления таблицы ProductInventory в образце базы данных AdventureWorks на основе заказов, обработанных в таблице SalesOrderDetail. Столбец Quantity таблицы ProductInventory обновляется путем вычитания количества заказов на каждый продукт, которые размещаются в течение дня в таблице SalesOrderDetail. Если количество заказов на продукт таково, что уровень запасов продукта опускается до нуля или становится еще ниже, то строка этого продукта удаляется из таблицы ProductInventory.

USE AdventureWorks;
GO
IF OBJECT_ID (N'Production.usp_UpdateInventory', N'P') IS NOT NULL DROP PROCEDURE Production.usp_UpdateInventory;
GO
CREATE PROCEDURE Production.usp_UpdateInventory
    @OrderDate datetime
AS
MERGE Production.ProductInventory AS target
USING (SELECT ProductID, SUM(OrderQty) FROM Sales.SalesOrderDetail AS sod
    JOIN Sales.SalesOrderHeader AS soh
    ON sod.SalesOrderID = soh.SalesOrderID
    AND soh.OrderDate = @OrderDate
    GROUP BY ProductID) AS source (ProductID, OrderQty)
ON (target.ProductID = source.ProductID)
WHEN MATCHED AND target.Quantity - source.OrderQty <= 0
    THEN DELETE
WHEN MATCHED 
    THEN UPDATE SET target.Quantity = target.Quantity - source.OrderQty, 
                    target.ModifiedDate = GETDATE()
OUTPUT $action, Inserted.ProductID, Inserted.Quantity, Inserted.ModifiedDate, Deleted.ProductID,
    Deleted.Quantity, Deleted.ModifiedDate;
GO

EXECUTE Production.usp_UpdateInventory '20030501'

В. Использование инструкции MERGE для выполнения операций UPDATE и INSERT применительно к целевой таблице с помощью производной исходной таблицы

В следующем примере инструкция MERGE используется для изменения таблицы SalesReason путем обновления или вставки строк. Если значение NewName в исходной таблице соответствует значению в столбце Name целевой таблицы (SalesReason), то в целевой таблице обновляется столбец ReasonType. Если значение NewName не совпадает со значением в целевой таблице, исходная строка вставляется в целевую таблицу. Исходная таблица является производной таблицей, в которой используется конструктор табличных значений Transact-SQL для указания нескольких строк исходной таблицы. Дополнительные сведения об использовании конструктора табличных значений в производной таблице см. в разделе конструктор табличных значений. В примере также показано, как сохранить результаты предложения OUTPUT в табличной переменной, а затем составить сводку результатов инструкцию MERGE, выполняя простую операцию выборки, которая возвращает количество вставленных и обновленных строк.

USE AdventureWorks;
GO
-- Create a temporary table variable to hold the output actions.
DECLARE @SummaryOfChanges TABLE(Change VARCHAR(20));

MERGE INTO Sales.SalesReason AS Target
USING (VALUES ('Recommendation','Other'), ('Review', 'Marketing'), ('Internet', 'Promotion'))
       AS Source (NewName, NewReasonType)
ON Target.Name = Source.NewName
WHEN MATCHED THEN
    UPDATE SET ReasonType = Source.NewReasonType
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Name, ReasonType) VALUES (NewName, NewReasonType)
OUTPUT $action INTO @SummaryOfChanges;

-- Query the results of the table variable.
SELECT Change, COUNT(*) AS CountPerChange
FROM @SummaryOfChanges
GROUP BY Change;

Г. Вставка результатов инструкции MERGE в другую таблицу

В следующем примере производится отслеживание данных, возвращаемых предложением OUTPUT инструкции MERGE, а затем осуществляется вставка этих данных в другую таблицу. Инструкция MERGE обновляет столбец Quantity таблицы ProductInventory с учетом заказов, обработанных в таблице SalesOrderDetail. В этом примере производится отслеживание обновляемых строк и их вставка в другую таблицу, которая используется для отслеживания изменений запасов.

USE AdventureWorks;
GO
CREATE TABLE Production.UpdatedInventory
    (ProductID INT NOT NULL, LocationID int, NewQty int, PreviousQty int,
     CONSTRAINT PK_Inventory PRIMARY KEY CLUSTERED (ProductID, LocationID));
GO
INSERT INTO Production.UpdatedInventory
SELECT ProductID, LocationID, NewQty, PreviousQty 
FROM
(    MERGE Production.ProductInventory AS pi
     USING (SELECT ProductID, SUM(OrderQty) 
            FROM Sales.SalesOrderDetail AS sod
            JOIN Sales.SalesOrderHeader AS soh
            ON sod.SalesOrderID = soh.SalesOrderID
            AND soh.OrderDate BETWEEN '20030701' AND '20030731'
            GROUP BY ProductID) AS src (ProductID, OrderQty)
     ON pi.ProductID = src.ProductID
    WHEN MATCHED AND pi.Quantity - src.OrderQty >= 0 
        THEN UPDATE SET pi.Quantity = pi.Quantity - src.OrderQty
    WHEN MATCHED AND pi.Quantity - src.OrderQty <= 0 
        THEN DELETE
    OUTPUT $action, Inserted.ProductID, Inserted.LocationID, Inserted.Quantity AS NewQty, Deleted.Quantity AS PreviousQty)
 AS Changes (Action, ProductID, LocationID, NewQty, PreviousQty) WHERE Action = 'UPDATE';
GO

Дополнительные примеры см. в разделах Добавление, обновление и удаление данных с помощью инструкции MERGE и Оптимизация производительности инструкции MERGE.