¿Hay alguna manera de pasar información al desencadenador Eliminar de modo que pueda saber quién eliminó el registro?
Sí: mediante el uso de una llamada muy interesante (y poco utilizada) CONTEXT_INFO
. Es esencialmente la memoria de sesión que existe en todos los ámbitos y no está vinculada por las transacciones. Se puede usar para pasar información (cualquier información, bueno, cualquiera que se ajuste al espacio limitado) a disparadores, así como de ida y vuelta entre llamadas subproc / EXEC. Y lo he usado antes para esta misma situación.
Pruebe con lo siguiente para ver cómo funciona. Tenga en cuenta que me estoy convirtiendo CHAR(128)
antes de CONVERT(VARBINARY(128), ..
. Esto es para forzar el relleno en blanco para que sea más fácil volver a convertirlo al VARCHAR
sacarlo, CONTEXT_INFO()
ya que VARBINARY(128)
está rellenado con 0x00
s.
SELECT CONTEXT_INFO();
-- Initially = NULL
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), 'I deleted ALL your records! HA HA!')
);
SET CONTEXT_INFO @EncodedUser;
SELECT CONTEXT_INFO() AS [RawContextInfo],
RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())) AS [DecodedUser];
Resultados:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
PONIENDOLO TODO JUNTO:
La aplicación debe llamar a un procedimiento almacenado "Eliminar" que pasa el nombre de usuario (o lo que sea) que está eliminando el registro. Supongo que este ya es el modelo que se está utilizando, ya que parece que ya está rastreando las operaciones de Insertar y Actualizar.
El procedimiento almacenado "Eliminar" hace:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
El disparador de auditoría hace:
-- Set the INT value in LEFT (currently 50) to the max size of [UserWhoMadeChanges]
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
SELECT del.ID, COALESCE(
LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50),
'<unknown>')
FROM DELETED del;
Tenga en cuenta que, como señaló @SeanGallardy en un comentario, debido a otros procedimientos y / o consultas ad hoc que eliminan registros de esta tabla, es posible que:
CONTEXT_INFO
no se ha configurado y sigue siendo NULL
:
Por esta razón, he actualizado lo anterior INSERT INTO AuditTable
para usar a COALESCE
para predeterminar el valor. O, si no desea un valor predeterminado y requiere un nombre, entonces podría hacer algo similar a:
DECLARE @UserName VARCHAR(50); -- set to the size of AuditTable.[UserWhoMadeChanges]
SET @UserName = LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50);
IF (@UserName IS NULL)
BEGIN
ROLLBACK TRAN; -- cancel the DELETE operation
RAISERROR('Please set UserName via "SET CONTEXT_INFO.." and try again.', 16 ,1);
END;
-- use @UserName in the INSERT...SELECT
CONTEXT_INFO
se ha establecido en un valor que no es un nombre de usuario válido y, por lo tanto, puede exceder el tamaño del AuditTable.[UserWhoMadeChanges]
campo:
Por esta razón, agregué una LEFT
función para garantizar que lo que sea que se extraiga CONTEXT_INFO
no rompa el INSERT
. Como se indica en el código, solo necesita establecer el 50
tamaño real del UserWhoMadeChanges
campo.
ACTUALIZACIÓN PARA SQL SERVER 2016 Y MÁS NUEVOS
SQL Server 2016 agregó una versión mejorada de esta memoria por sesión: Contexto de sesión. El nuevo contexto de sesión es esencialmente una tabla hash de pares clave-valor, siendo la "clave" del tipo sysname
(es decir NVARCHAR(128)
) y el "valor" SQL_VARIANT
. Sentido:
- Ahora hay una separación de valores, por lo que es menos probable que entre en conflicto con otros usos
- Puede almacenar varios tipos, ya no necesita preocuparse por el comportamiento extraño al recuperar el valor a través de
CONTEXT_INFO()
(para más detalles, consulte mi publicación: ¿Por qué no CONTEXT_INFO () devuelve el valor exacto establecido por SET CONTEXT_INFO? )
- Obtiene mucho más espacio: 8000 bytes como máximo por "Valor", hasta 256 kb en total en todas las claves (en comparación con los 128 bytes como máximo
CONTEXT_INFO
)
Para más detalles, consulte las siguientes páginas de documentación:
SUSER_SNAME()
es la clave para obtener quién borró el registro.