Подтвердить что ты не робот

Как вы получаете значение идентификатора после использования MERGE, когда есть совпадение?

Скажем, у меня есть таблица с полем идентификации. Я хочу вставить в него запись, если она еще не существует. В приведенном ниже примере я проверяю, существует ли в таблице значение, хранящееся в @Field1. Если нет, я вставляю новую запись:

Определение таблицы:

MyTable (MyTableId int Identity not null, Field1 int not null, Field2 int not null)  

Вот как я проверяю, существует ли уже существующее значение и при необходимости вставьте его

merge MyTable as t
using (@Field1, @Field2) as s (Field1,Field2)
on (t.Field1=s.Field1)
when not matched then
    insert (Field1,Field2) values (s.Field1,s.Field2);

Получение значения идентификатора, когда запись еще не существует в таблице, может быть выполнена путем добавления:

output Inserted.MyTableId  

но что, если запись уже была в таблице (т.е. если была совпадение)?

Единственный способ, которым я нашел, - запросить таблицу после выполнения оператора Merge:

select MyTableId from MyTable where [email protected]

Есть ли способ получить значение идентичности непосредственно из Merge?

4b9b3361

Ответ 1

В случае, когда запись уже существует, вы можете сохранить совпадающий идентификатор в переменную следующим образом:

DECLARE @MatchedId INTEGER;

MERGE MyTable as t
....
....
WHEN MATCHED THEN
    UPDATE SET @MatchedId = t.MyTableId;

UPDATE:
Вот полный пример. Это демонстрирует один из способов:

DECLARE @UpdateVariable bit
DECLARE @ChangeResult TABLE (ChangeType VARCHAR(10), Id INTEGER)
DECLARE @Data TABLE (Id integer IDENTITY(1,1), Val VARCHAR(10))
INSERT @Data ([Val]) VALUES ('A');

MERGE @data AS TARGET
USING (SELECT 'A' AS Val UNION ALL SELECT 'B' AS Val) AS SOURCE ON TARGET.Val = SOURCE.Val
WHEN NOT MATCHED THEN
    INSERT ([Val])
    VALUES (SOURCE.Val)
WHEN MATCHED THEN 
    UPDATE SET @UpdateVariable = 1
OUTPUT $action, inserted.Id INTO @ChangeResult;

SELECT * FROM @data
SELECT * FROM @ChangeResult

Следует отметить:

  • $action даст вам, какое действие было выполнено для строки (INSERT, UPDATE, DELETE)
  • @ChangeResult будет содержать информацию о том, какие изменения были сделаны.
  • для случая WHEN MATCHED, я в основном устанавливаю фиктивную переменную. Это не служит никакой цели здесь, кроме как обеспечить, чтобы путь UPDATE попал для создания строки UPDATE на выходе. т.е. что @UpdateVariable не используется ни для чего другого. Если вы действительно хотели обновить существующую строку, тогда вы разместите здесь надлежащий UPDATE, но в случае, если вы не хотите обновлять существующую строку, это обновление "dummy", как представляется, требуется.

Ответ 2

Вот альтернативный и немного более простой подход (на мой взгляд):

DECLARE @Id [int];

MERGE INTO [MyTable] AS [t]
USING (VALUES
  (@FieldA, @FieldB)
)
 AS [x] (FieldA, FieldB)
 ON [t].[FieldA] = [x].[FieldA]
AND [t].[FieldB] = [x].[FieldB]
WHEN NOT MATCHED BY TARGET THEN
    INSERT (FieldA, FieldB)
    VALUES (FieldA, FieldB)
WHEN MATCHED THEN
    UPDATE SET @Id = [t].[Id]

IF @Id IS NULL
BEGIN
    SET @Id = CAST(SCOPE_IDENTITY() as [int]);
END
SELECT @Id;

Если оператор слияния привел к совпадению, тогда @Id будет установлено личность соответствующей строки. В случае отсутствия соответствия новая строка будет вставлена ​​с ее новым идентификатором, готовым к выбору из SCOPE_IDENTITY().