Disparadores SQL - ¿eliminados o actualizados? ¿O tal vez algo más?
-
26-10-2019 - |
Pregunta
Estoy tratando de averiguar qué necesito usar aquí: eliminado, insertado o actualizado.
básicamente.
Necesito escribir algunos datos en la tabla del historial, cuando se actualiza la tabla principal, y solo si el estado cambia de algo a pendiente o activo.
Esto es lo que tengo ahora:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE AS
DECLARE @statusOldValue char(1)
DECLARE @statusNewValue char(1)
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
IF (@statusOldValue <> @statusNewValue) AND
(@statusOldValue = 'P' or @statusOldValue = 'A')
BEGIN TRY
INSERT * INTO tblHistoryTable)
select * from [DELETED]
Por lo tanto, quiero que los nuevos datos permanezcan en la tabla principal, la tabla de historial se actualiza con lo que se está sobrescribiendo ... en este momento simplemente copia la misma información. Entonces, después de la actualización, ambas tablas tienen los mismos datos.
Solución
Necesitas usar ambos inserted
y deleted
tablas juntas para verificar los registros que:
1. Ya existió (para verificar que no sea un inserto)
2. Todavía existe (para verificar que no sea un eliminación)
3. El campo de estado cambió
También debe asegurarse de hacerlo en un enfoque basado en un conjunto, según la respuesta de Marc_S, los desencadenantes no son procesos de registro únicos.
INSERT INTO
tblHistoryTable
SELECT
deleted.*
FROM
inserted
INNER JOIN
deleted
ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
inserted.StatusCode <> deleted.StatusCode
AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
- insertado = los nuevos valores
- eliminado = los valores antiguos
Otros consejos
Solo hay el Inserted
y Deleted
pseudo mesas - no hay Updated
.
Por un UPDATE
, Inserted
contiene los nuevos valores (después de la actualización) mientras Deleted
Contiene los valores antiguos antes de la actualización.
También ser consciente que se disparan los desencadenantes Una vez por lote - Ni una sola vez para cada fila. Entonces ambas pseudo mesas contendrán potencialmente múltiples filas! No asuma una sola fila y asigne esto a una variable, esta
SELECT @statusOldValue = statusCode FROM deleted
SELECT @statusNewValue= statusCode FROM updated
fallará ¡Si tienes varias filas! Necesitas escribir tus desencadenantes de tal manera que trabajan múltiples filas en Inserted
y Deleted
!
Actualizar: si ahí ES Una manera mucho mejor de escribir esto:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE
AS
INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
SELECT Col1, COl2, Col3, ..... ColN
FROM Deleted d
INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
WHERE i.statusCode <> d.statusCode
AND d.statusCode IN ('A', 'P')
Básicamente:
Especifique explícitamente las columnas que desea insertar, ambas en el
INSERT
declaración y elSELECT
Declaración recuperando los datos para insertar: para evitar cualquier sorpresa desagradablecrear un
INNER JOIN
EntreInserted
yDeleted
Pseudo-tablas para obtener todas las filas que se actualizaronespecificar todas las demás condiciones (diferentes códigos de estado, etc.) en el
WHERE
cláusula delSELECT
Esta solución funciona para lotes de filas que se actualizan: no fallará en una actualización de múltiples filas ...
No hay updated
mesa, estás buscando inserted
.