触发插入 table 中的数据保留以及在一列上更新和插入的组合
Triggers data retention in inserted table and combination of update and insert on one column
我在 SQL 服务器中有一个 table,其中包含所有数据的快照以跟踪源 table tbl_D_project
状态的变化。如果此状态发生变化或在 tbl_D_project
中添加了新记录,则应启动触发器并将该行复制到快照 table。
我根据我在这里发现的另一个问题写了两个触发器。一种用于更新,一种用于插入。我的问题是:
有没有更高效的方法?我能否以某种方式将两者合二为一,以便插入后更新?
多个用户同时提交数据。数据在插入的table中停留了多长时间?是否有可能如果两个用户提交数据,触发器将被触发两次,因此这些行将被复制两次到快照table?
更新触发后:
ALTER TRIGGER [dbo].[tr_copysnapshot_update]
ON [CDB].[dbo].[tbl_D_project]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
INNER JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
D.[Status] <> I.[Status]
END
插入触发器后:
ALTER TRIGGER [dbo].[tr_copysnapshot_insert]
ON [CBD].[dbo].[tbl_D_project]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID,
Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
WHERE
S.[Opp_ID] = I.[Opp_ID]
END
SQL update trigger only when column is modified
是的,你可以组合触发器,只需使用 LEFT JOIN
到内存驻留 table deleted
,并更改你的 where 子句,这样你只添加一行如果状态更改(更新)或删除(插入)中没有记录,即
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
LEFT JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
(D.[Status] <> I.[Status] OR d.Opp_ID IS NULL)
关于你的第二个问题,你所描述的是不可能的,两个用户不能同时进行相同的更新,即使只是相隔几微秒,它仍然会先做一个再做另一个(每个会有它自己的 inserted/deleted table),所以是的,这总是会触发触发器两次。
如果两个用户都执行相同的更新,那么您的 where 子句规定状态必须已更改将阻止第二次插入。如果你想扩展它以在其他列发生变化时捕获记录,但如果没有任何变化,你可以使用以下 WHERE
子句:
WHERE NOT EXISTS (SELECT i.* INTERSECT SELECT d.*)
通常我不建议组合触发器,因为代码通常完全不同。但在这种情况下,代码很简单。
- 请注意在子查询的第一部分使用虚拟 table(
SELECT
,没有 FROM
)。
- 我们总是需要比较主键,所以我们把它放在子查询中
CREATE OR ALTER TRIGGER [dbo].[tr_copysnapshot]
ON [CDB].[dbo].[tbl_D_project]
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON S.Opp_id = I.Opp_ID
WHERE NOT EXISTS (
SELECT I.Opp_ID, I.[Status]
INTERSECT
SELECT D.Opp_ID, D.[Status]
FROM deleted d);
GO
我在 SQL 服务器中有一个 table,其中包含所有数据的快照以跟踪源 table tbl_D_project
状态的变化。如果此状态发生变化或在 tbl_D_project
中添加了新记录,则应启动触发器并将该行复制到快照 table。
我根据我在这里发现的另一个问题写了两个触发器。一种用于更新,一种用于插入。我的问题是:
有没有更高效的方法?我能否以某种方式将两者合二为一,以便插入后更新?
多个用户同时提交数据。数据在插入的table中停留了多长时间?是否有可能如果两个用户提交数据,触发器将被触发两次,因此这些行将被复制两次到快照table?
更新触发后:
ALTER TRIGGER [dbo].[tr_copysnapshot_update]
ON [CDB].[dbo].[tbl_D_project]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
INNER JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
D.[Status] <> I.[Status]
END
插入触发器后:
ALTER TRIGGER [dbo].[tr_copysnapshot_insert]
ON [CBD].[dbo].[tbl_D_project]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID,
Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
WHERE
S.[Opp_ID] = I.[Opp_ID]
END
SQL update trigger only when column is modified
是的,你可以组合触发器,只需使用 LEFT JOIN
到内存驻留 table deleted
,并更改你的 where 子句,这样你只添加一行如果状态更改(更新)或删除(插入)中没有记录,即
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON s.opp_id = I.Opp_ID
LEFT JOIN
Deleted D ON s.opp_ID = D.Opp_ID
WHERE
(D.[Status] <> I.[Status] OR d.Opp_ID IS NULL)
关于你的第二个问题,你所描述的是不可能的,两个用户不能同时进行相同的更新,即使只是相隔几微秒,它仍然会先做一个再做另一个(每个会有它自己的 inserted/deleted table),所以是的,这总是会触发触发器两次。
如果两个用户都执行相同的更新,那么您的 where 子句规定状态必须已更改将阻止第二次插入。如果你想扩展它以在其他列发生变化时捕获记录,但如果没有任何变化,你可以使用以下 WHERE
子句:
WHERE NOT EXISTS (SELECT i.* INTERSECT SELECT d.*)
通常我不建议组合触发器,因为代码通常完全不同。但在这种情况下,代码很简单。
- 请注意在子查询的第一部分使用虚拟 table(
SELECT
,没有FROM
)。 - 我们总是需要比较主键,所以我们把它放在子查询中
CREATE OR ALTER TRIGGER [dbo].[tr_copysnapshot]
ON [CDB].[dbo].[tbl_D_project]
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT INTO cbdbpc.dbo.[Snapshot_tbl_D_project]
(Snapshot_date, Opp_ID, Reference_ID, Project_ID, Project_opportunity, [State], [Status])
SELECT
GETDATE(), S.Opp_ID, S.Reference_ID, S.Project_ID,
S.Project_opportunity, S.[State], S.[Status]
FROM
cbdbpc.dbo.[tbl_D_project] S
INNER JOIN
Inserted I ON S.Opp_id = I.Opp_ID
WHERE NOT EXISTS (
SELECT I.Opp_ID, I.[Status]
INTERSECT
SELECT D.Opp_ID, D.[Status]
FROM deleted d);
GO