使用触发器如何复制刚刚插入的行

Posted

技术标签:

【中文标题】使用触发器如何复制刚刚插入的行【英文标题】:Use trigger how to copy just inserted row 【发布时间】:2013-01-15 08:45:49 【问题描述】:

我正在使用 SQL Server 2008,并且我有一个触发器,我想将 My_Table 中的任何行复制到存档 History_Table 表中。

每次有人插入新行时,如何将表的整个旧内容复制到存档中?

我的表结构是

    CREATE TABLE [dbo].[Stu_Table]
    (
    [Stu_Id] [int] NOT NULL,
    [Stu_Name] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Stu_Class] [int] NULL
    ) ON [PRIMARY]
    GO

ALTER TABLE [dbo].[Stu_Table] ADD CONSTRAINT [PK_Stu_Table] PRIMARY KEY CLUSTERED  ([Stu_Id]) ON [PRIMARY]
GO

我的存档表结构是

CREATE TABLE [dbo].[Stu_TableHistory]
(
[Stu_Id] [int] NOT NULL,
[Stu_Name] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Stu_Class] [int] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Stu_TableHistory] ADD CONSTRAINT [PK_Stu_TableHistory] PRIMARY KEY CLUSTERED  ([Stu_Id]) ON [PRIMARY]
GO

我的触发器语法是

Create TRIGGER [dbo].[HistoryKeep]
   ON  [dbo].[Stu_Table]
   INSTEAD OF  INSERT
AS 
BEGIN
    IF((SELECT COUNT(*) FROM Stu_Table WHERE Stu_Id = (SELECT Stu_Id FROM INSERTED)) >= 1)
    BEGIN
        INSERT INTO dbo.Stu_TableHistory( Stu_Id, Stu_Name, Stu_Class )
        SELECT Stu_Id, Stu_Name, Stu_Class FROM Stu_Table WHERE Stu_Id = (SELECT Stu_Id FROM INSERTED)

        UPDATE x
        SET x.Stu_Name = i.Stu_Name
        FROM dbo.Stu_Table AS x
        INNER JOIN inserted AS i ON i.Stu_Id = x.Stu_Id

    END
    ELSE
    BEGIN
        INSERT INTO dbo.Stu_Table( Stu_Id, Stu_Name, Stu_Class )
        SELECT Stu_Id, Stu_Name, Stu_Class FROM INSERTED
    END
END

总之需要帮助将旧数据从学生表转移到存档表。我上面的触发器语法不能满足我。

如果有任何疑问请提前询问。

【问题讨论】:

INSERTED 是一个伪表,可以包含多个行。您需要编写接受该现实的查询。假设 SELECT STU_ID from INSERTED 将返回 1 个结果,您的代码被破坏了。它可能包含混合行——一些行适合UPDATE,另一些适合普通的INSERT Damien_The_Unbeliever 感谢您的回复,不明白您的评论描述,请您分享一些详细描述的语法。谢谢 查看***.com/questions/3336319/… 请参阅此处以获取有关 InsertedDeleted 表的文档:msdn.microsoft.com/en-us/library/ms191300.aspx 【参考方案1】:

你应该有类似的东西,而不是你当前的触发器:

Create TRIGGER [dbo].[HistoryKeep]
   ON  [dbo].[Stu_Table]
   INSTEAD OF  INSERT
AS 
BEGIN
DECLARE @History table (
    Action sysname not null,
    STU_ID [int] NULL,
    [Stu_Name] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Stu_Class] [int] NULL
)

;MERGE INTO Stu_Table t
USING INSERTED i ON t.STU_ID = i.STU_ID
WHEN MATCHED THEN UPDATE SET STU_Name = i.STU_Name
WHEN NOT MATCHED THEN INSERT (STU_ID,STU_NAME,STU_CLASS) VALUES (i.STU_ID,i.STU_NAME,i.STU_CLASS)
OUTPUT $Action,deleted.stu_id,deleted.stu_name,deleted.stu_class INTO @History;

INSERT INTO stu_TableHistory (stu_id,stu_name,stu_class)
select stu_id,stu_name,stu_class from @History where Action='UPDATE'
END

另外请注意,您需要删除当前对 STU_TableHistory 的 PK 约束,因为只要一行更新不止一次,就会有两个条目包含相同的 STU_ID


根据我的评论,这会将INSERTED 视为一个包含多行的表格。因此,如果Stu_Table 包含STU_ID 1 的行,则插入以下内容:

INSERT INTO STU_Table (STU_ID,STU_Name,STU_Class) VALUES
(1,'abc',null),
(2,'def',null)

更新STU_ID 1 的行,插入STU_ID 2 的行,并将一个 行插入@987654330 @(对于STU_ID 1)

【讨论】:

以上是关于使用触发器如何复制刚刚插入的行的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server“AFTER INSERT”触发器看不到刚刚插入的行

如何编写 MySQL 触发器以将行插入另一个表?

创建计算每个新插入员工的总工资的行级触发器

如何使用插入触发器后更新表字段?

Mysql - 创建触发器以根据插入另一个表中的行插入新行

插入触发器最终在分区表中插入重复的行