2012-05-18 12 views
26

Supongamos que tengo una tabla con un campo de identidad. Quiero insertar un registro si aún no existe. En el siguiente ejemplo, verifico si el valor almacenado en @ Field1 ya existe en la tabla. Si no, insertar un nuevo registro:¿Cómo se obtiene el valor de identidad después de usar MERGE cuando hay una coincidencia?

Definición de la tabla:

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

Así es como puedo comprobar si el valor ya existe y la inserto en caso necesario

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); 

Conseguir la identidad el valor cuando el registro no existía en la tabla se puede hacer al agregar:

output Inserted.MyTableId 

pero ¿y si el registro ya estaba en la mesa (es decir, si había una coincidencia)?

La única manera que he encontrado es para consultar la tabla después de ejecutar la instrucción MERGE:

select MyTableId from MyTable where [email protected] 

¿Hay una manera de obtener el valor de identidad directamente de la fusión?

Respuesta

25

En el caso de que ya existe el registro, puede almacenar el id emparejado en una variable de la siguiente manera:

DECLARE @MatchedId INTEGER; 

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

ACTUALIZACIÓN:
He aquí un ejemplo completo. Esto demuestra una manera:

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 

Puntos a tener en cuenta son:

  • $ acción le dará qué tipo de acción se llevó a cabo para una fila (INSERT, UPDATE, DELETE)
  • mesa @ChangeResult mantendrá la información en cuanto a qué tipos de cambios se hicieron
  • para el caso CUANDO ESTÁN IGUALADOS, básicamente estoy configurando una variable ficticia. Esto no sirve para otro propósito que no sea asegurar que la ruta UPDATE se golpee para generar la fila UPDATE en la salida. es decir, que @UpdateVariable no se usa para nada más. Si realmente desea actualizar la fila existente, debe colocar una ACTUALIZACIÓN adecuada aquí, pero en el caso donde no desee ACTUALIZAR realmente la fila existente, entonces esta actualización "ficticia" parece ser necesaria.
+1

Gracias Adrian, pero si no hay coincidencia, ¿cómo se obtiene el nuevo valor de identidad en @MatchedId? – Anthony

+4

Gracias por la actualización. Sí, esto funcionaría, pero parece que es mucho más código que simplemente hacer "seleccionar MyTableId desde MyTable donde Field1 = @ Field1" después de la combinación (obviamente depende del tamaño de la tabla real, etc.).Solo esperaba que hubiera una solución 'incorporada' en la declaración Merge que devolvería el valor de identidad en ambos casos (igual o no coincide). – Anthony

17

Aquí es un enfoque alternativo y un poco más sencillo (en mi opinión):

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; 

Si la instrucción de combinación resultó en un partido a continuación @Id se establecerá en la identidad de la fila coincidente. En caso de que no coincida, la nueva fila se insertará con su nueva identidad, lista para ser seleccionada desde SCOPE_IDENTITY().

Cuestiones relacionadas