tengo otra solución completamente diferente que no utiliza COLUMNS_UPDATED en absoluto, ni se basa en la construcción de SQL dinámico en tiempo de ejecución. (Es posible que desee utilizar SQL dinámico en el momento del diseño, pero esa es otra historia).
Básicamente, comience con the inserted and deleted tables, desvincule cada uno de ellos para que quede con la clave única, el valor del campo y las columnas del nombre del campo para cada uno. Luego te unes a los dos y filtra por cualquier cosa que haya cambiado.
Aquí es un ejemplo de trabajo completo, incluyendo algunas llamadas de prueba para mostrar lo que se registra.
-- -------------------- Setup tables and some initial data --------------------
CREATE TABLE dbo.Sample_Table (ContactID int, Forename varchar(100), Surname varchar(100), Extn varchar(16), Email varchar(100), Age int);
INSERT INTO Sample_Table VALUES (1,'Bob','Smith','2295','[email protected]',24);
INSERT INTO Sample_Table VALUES (2,'Alice','Brown','2255','[email protected]',32);
INSERT INTO Sample_Table VALUES (3,'Reg','Jones','2280','[email protected]',19);
INSERT INTO Sample_Table VALUES (4,'Mary','Doe','2216','[email protected]',28);
INSERT INTO Sample_Table VALUES (5,'Peter','Nash','2214','[email protected]',25);
CREATE TABLE dbo.Sample_Table_Changes (ContactID int, FieldName sysname, FieldValueWas sql_variant, FieldValueIs sql_variant, modified datetime default (GETDATE()));
GO
-- -------------------- Create trigger --------------------
CREATE TRIGGER TriggerName ON dbo.Sample_Table FOR DELETE, INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON;
--Unpivot deleted
WITH deleted_unpvt AS (
SELECT ContactID, FieldName, FieldValue
FROM
(SELECT ContactID
, cast(Forename as sql_variant) Forename
, cast(Surname as sql_variant) Surname
, cast(Extn as sql_variant) Extn
, cast(Email as sql_variant) Email
, cast(Age as sql_variant) Age
FROM deleted) p
UNPIVOT
(FieldValue FOR FieldName IN
(Forename, Surname, Extn, Email, Age)
) AS deleted_unpvt
),
--Unpivot inserted
inserted_unpvt AS (
SELECT ContactID, FieldName, FieldValue
FROM
(SELECT ContactID
, cast(Forename as sql_variant) Forename
, cast(Surname as sql_variant) Surname
, cast(Extn as sql_variant) Extn
, cast(Email as sql_variant) Email
, cast(Age as sql_variant) Age
FROM inserted) p
UNPIVOT
(FieldValue FOR FieldName IN
(Forename, Surname, Extn, Email, Age)
) AS inserted_unpvt
)
--Join them together and show what's changed
INSERT INTO Sample_Table_Changes (ContactID, FieldName, FieldValueWas, FieldValueIs)
SELECT Coalesce (D.ContactID, I.ContactID) ContactID
, Coalesce (D.FieldName, I.FieldName) FieldName
, D.FieldValue as FieldValueWas
, I.FieldValue AS FieldValueIs
FROM
deleted_unpvt d
FULL OUTER JOIN
inserted_unpvt i
on D.ContactID = I.ContactID
AND D.FieldName = I.FieldName
WHERE
D.FieldValue <> I.FieldValue --Changes
OR (D.FieldValue IS NOT NULL AND I.FieldValue IS NULL) -- Deletions
OR (D.FieldValue IS NULL AND I.FieldValue IS NOT NULL) -- Insertions
END
GO
-- -------------------- Try some changes --------------------
UPDATE Sample_Table SET age = age+1;
UPDATE Sample_Table SET Extn = '5'+Extn where Extn Like '221_';
DELETE FROM Sample_Table WHERE ContactID = 3;
INSERT INTO Sample_Table VALUES (6,'Stephen','Turner','2299','[email protected]',25);
UPDATE Sample_Table SET ContactID = 7 where ContactID = 4; --this will be shown as a delete and an insert
-- -------------------- See the results --------------------
SELECT *, SQL_VARIANT_PROPERTY(FieldValueWas, 'BaseType') FieldBaseType, SQL_VARIANT_PROPERTY(FieldValueWas, 'MaxLength') FieldMaxLength from Sample_Table_Changes;
-- -------------------- Cleanup --------------------
DROP TABLE dbo.Sample_Table; DROP TABLE dbo.Sample_Table_Changes;
Así que no jugar un poco con campos de bits bigint y problemas de desbordamiento de Arth. Si conoce las columnas que desea comparar en tiempo de diseño, entonces no necesita ningún SQL dinámico.
En la parte inferior, la salida está en un formato diferente y todos los valores de campo se convierten a sql_variant, el primero se puede arreglar girando nuevamente la salida y el segundo se puede arreglar volviendo a los tipos necesarios en función de su conocimiento del diseño de la tabla, pero ambos requerirían algunos sql dinámicos complejos. Ambos pueden no ser un problema en su salida XML.
Edición: Revisión de los comentarios a continuación, si tiene una clave principal natural que podría cambiar a continuación, puede seguir utilizando este método. Solo necesita agregar una columna que se completa de manera predeterminada con un GUID que usa la función NEWID(). A continuación, usa esta columna en lugar de la clave principal.
Es posible que desee añadir un índice en este campo, pero a medida que las tablas eliminadas e insertadas en un disparador están en la memoria no puede acostumbrarse y puede tener un efecto negativo en el rendimiento.
Gracias por la respuesta, sin embargo, la unión es muy costosa a este nivel teniendo en cuenta los cambios enormes, así que no voy a utilizarlo como estoy tratando de descubrir algo en el seguimiento de cambios, pero gracias de todos modos. –
Bueno, pero para información, cuando hay una brecha en column_id en sys.columns (por ejemplo, de columna eliminada), el código anterior no lo detecta. Ej. Con una tabla de 26 columnas, el resultado es [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [23] [24] [25] [26] [27] mientras que no hay columna con column_id = 9 – Yahia
no está funcionando como se esperaba. En algún momento funciona para 1 campo, a veces funciona, a veces falla por completo (en función de la consulta, pero no de la salida aleatoria para la misma consulta). ¡Estoy usando SQL server 2014 (120)! – SKLTFZ