sql >> Base de Datos >  >> RDS >> Sqlserver

Registro de la operación de actualización en disparadores

Antes de responder, permítanme decir primero que no creo que sea mejor registrar todas las tablas en una sola tabla. Si su base de datos crece, podría terminar con una seria disputa en la tabla de registro. Además, todos sus datos deben cambiarse a varchar o sql_variant para colocarlos en la misma columna, lo que obliga a ocupar más espacio. También creo que registrar cada columna actualizada en una fila separada (saltando las columnas que no están actualizadas) hará que sea muy Difícil de consultar. ¿Sabe cómo reunir todos esos datos para obtener una vista compuesta y sensata de los cambios de cada fila, cuándo y por quién? Tener una tabla de registro por tabla es, en mi opinión, mucho más fácil. Entonces no tendrás los problemas que estás experimentando al intentar que funcione.

Además, ¿sabía usted acerca de SQL Server 2008 Cambiar captura de datos ? ¡Utilícelo en su lugar, si está utilizando las ediciones Enterprise o Developer de SQL Server!

Aparte de ese problema, puede hacer lo que quiera con un UNPIVOT lógico (realizando su propia versión). Realmente no puede usar Native SQL 2005 UNPIVOT porque tiene dos columnas de destino, no una. Aquí hay un ejemplo para SQL Server 2005 y versiones posteriores usando CROSS APPLY para realizar UNPIVOT:

INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT 12345, I.Id, X.Id_Value, X.Old_Value, X.New_Value
FROM
   INSERTED I 
   INNER JOIN DELETED D ON I.ID = D.ID
   CROSS APPLY (
      SELECT 4556645, D.Name, I.Name
      UNION ALL SELECT 544589, D.Surname, I.Surname
    ) X (Id_Value, Old_Value, New_Value)
WHERE
   X.Old_Value <> X.New_Value

Aquí hay un método más genérico para SQL 2000 u otros DBMS (teóricamente debería funcionar en Oracle, MySQL, etc. -- para Oracle agregue FROM DUAL a cada SELECT en la tabla derivada):

INSERT INTO dbo.LOG (Id_Table, Table_Key_Value, Id_Value, Old_Value, New_Value)
SELECT *
FROM (
   SELECT
      12345,
      I.Id,
      X.Id_Value,
      CASE X.Id_Value
         WHEN 4556645 THEN D.Name
         WHEN 544589 THEN D.Surname
      END Old_Value,
      CASE X.Id_Value
         WHEN 4556645 THEN I.Name
         WHEN 544589 THEN I.Surname
      END New_Value   
   FROM
      INSERTED I 
      INNER JOIN DELETED D ON I.ID = D.ID
      CROSS JOIN (
         SELECT 4556645
         UNION ALL SELECT 544589
      ) X (Id_Value)
) Y
WHERE
   Y.Old_Value <> Y.New_Value

SQL Server 2005 y versiones posteriores tienen el comando UNPIVOT nativo, aunque en general, incluso cuando UNPIVOT funcionará, me gusta usar CROSS APPLY en su lugar porque hay más flexibilidad para hacer lo que quiero. Específicamente, el comando UNPIVOT nativo no funciona aquí porque UNPIVOT solo puede apuntar a una sola columna de destino, pero necesita dos (Old_Value, New_Value). Concatenar las dos columnas en un solo valor (y separarlas después) no es bueno; crear un valor de correlador de fila sin sentido para PIVOT después no es bueno, y no puedo pensar en otra forma de hacerlo que no sea una variación de esos dos. La solución CROSS APPLY realmente será la mejor para que coincida con la estructura exacta de la tabla de registro que ha descrito.

En comparación con mis consultas aquí, su método n. ° 1 no funcionará tan bien (en una proporción de aproximadamente {el número de columnas}:1 peor rendimiento). Su método n.º 2 es una buena idea, pero sigue siendo subóptimo porque llamar a un UDF tiene una gran sobrecarga, además de que tiene que recorrer cada fila (estremecerse).