SQL 触发器 - 删除还是更新?或者也许是别的什么?

发布于 2024-11-26 09:43:33 字数 677 浏览 0 评论 0原文

我想弄清楚我需要在这里使用哪个:删除、插入或更新。

基本上。

当主表更新时,并且仅当状态从某项更改为挂起或活动时,我需要将一些数据写入历史表。

这就是我现在所拥有的:

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]

所以我希望新数据保留在主表中,历史表要使用被覆盖的内容进行更新......现在它只是复制相同的信息。所以更新后,我的两个表都有相同的数据。

I am trying to figure out which i need to use here: deleted, inserted or updated.

basically.

I need to write some data to the history table, when the main table is updated, and only if the status changes from something to either pending or active.

This is what I have now:

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]

so I want the new data to stay in the main table, the the history table to be updated with what is being overwritten... right now it just copies the same info over. so after update, both my tables have the same data.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事未完 2024-12-03 09:43:34

只有 InsertedDeleted 伪表 - 没有 Updated

对于 UPDATEInserted 包含新值(更新后),而 Deleted 包含更新前的旧值。

另请注意,触发器每批触发一次 - 而不是每行触发一次。因此,两个伪表都可能包含多行!不要只假设一行并将其分配给一个变量 -

SELECT @statusOldValue = statusCode FROM deleted 
SELECT @statusNewValue= statusCode FROM updated

如果您有多行,这将会失败!您需要以这样的方式编写触发器,使其能够在 InsertedDeleted 中处理多行

更新:是的 - IS有一种更好的写法:

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')

基本上:

  • 明确指定要插入的列 - 都在 INSERT< /code> 语句以及检索要插入的数据的 SELECT 语句 - 以避免任何令人讨厌的意外

  • InsertedDeleted 之间创建一个 INNER JOIN code> 伪表来获取所有已更新的行

  • SELECTWHERE 子句中指定所有其他条件(不同的状态代码等)

此解决方案适用于正在更新的批量行 - 它不会在多行更新上失败......

There are only the Inserted and Deleted pseudo tables - there's no Updated.

For an UPDATE, Inserted contains the new values (after the update) while Deleted contains the old values before the update.

Also be aware that the triggers is fired once per batch - not once for each row. So both pseudo tables will potentially contain multiple rows! Don't just assume a single row and assign this to a variable - this

SELECT @statusOldValue = statusCode FROM deleted 
SELECT @statusNewValue= statusCode FROM updated

will fail if you have multiple rows ! You need to write your triggers in such a fashion that they work with multiple rows in Inserted and Deleted !

Update: yes - there IS a much better way to write this:

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')

Basically:

  • explicitly specify the columns you want to insert - both in the INSERT statement as well as the SELECT statement retrieving the data to insert - to avoid any nasty surprises

  • create an INNER JOIN between Inserted and Deleted pseudo-tables to get all rows that were updated

  • specify all other conditions (different status codes etc.) in the WHERE clause of the SELECT

This solution works for batches of rows being updated - it won't fail on a multi-row update....

捎一片雪花 2024-12-03 09:43:34

您需要同时使用inserteddeleted 表来检查以下记录:
1. 已经存在(检查它不是插入)
2.仍然存在(检查它不是删除)
3.状态字段已更改

您还需要确保以基于集合的方法执行此操作,根据 marc_s 的回答,触发器不是单个记录进程。

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')
  • 插入 = 新值
  • 删除 = 旧值

You need to use both the inserted and deleted tables together to check for records that:
1. Already existed (to check it's not an insert)
2. Still exists (to check it's not a delete)
3. The Status field changed

You also need to make sure you do that in a set based approach, as per marc_s's answer, triggers are not single record processes.

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')
  • inserted = the new values
  • deleted = the old values
秉烛思 2024-12-03 09:43:34

没有更新表,您正在寻找插入

There is no updated table, you are looking for inserted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文