【问题标题】:Delete records within Instead Of Delete trigger删除而不是删除触发器中的记录
【发布时间】:2011-03-17 00:50:53
【问题描述】:

我想要一个而不是删除触发器,以便我可以从要删除的表行中获取文本字段值,以便在实际删除发生时保留这些字段。由于某种原因,我无法在标准 Delete 触发器中将它们从 Deleted 表中拉出(SQL 错误输出)。

有没有办法在“而不是删除”触发器中进行实际删除而不使触发器重新触发?

或者在删除一行以保存到新记录后获取文本字段的更好方法?

【问题讨论】:

  • 如果我不说别人会说,那么就这样吧。 “你能在存储过程中做到这一点吗?为什么要使用触发器而不是在删除之前选择记录?”
  • 如果您在使用现有代码时遇到问题,也许您可​​以在此处显示该代码。也许有人会发现错误。

标签: sql sql-server triggers delete-row


【解决方案1】:

上面的答案都不适合我,我假设人们使用的是 SQL 2008,所以这个答案适用于 SQL 2012

CREATE TRIGGER People_LogTriggerDelete ON People
INSTEAD OF DELETE
AS
SET NOCOUNT ON;
INSERT INTO People_AuditLog (Event, Date, Id, Name, LastName, SqlUser)
       SELECT 'DELETE', GETDATE(), d.Id, d.Name, d.LastName, CONCAT(SUSER_SNAME(),'/',@@SERVERNAME)
       FROM People t INNER JOIN deleted d ON t.Id = d.Id

DELETE People FROM People JOIN deleted ON People.Id = deleted.Id

【讨论】:

    【解决方案2】:

    这个方法应该可以解决问题。而不是触发器将执行您指定的任何操作,而不是自动执行删除。这意味着您手动删除它是关键,否则记录将不会被删除。它不会递归运行。它只能在没有启用级联删除的表上完成。基本上,诀窍是您加入 id 字段上的原始表,以便从已删除的伪表中您无权访问的字段中获取数据。

    create table dbo.mytesting (test_id int, sometext text)
    go
    create table dbo.myaudit (test_id int, sometext text)
    go
    insert into dbo.mytesting
    values (1, 'test')
    go
    
    Create Trigger audit_Table_Deletes on dbo.mytesting INSTEAD OF delete  
    as 
    if @@rowcount = 0 return; 
    Insert into dbo.myaudit (test_id, sometext) 
    Select d.test_id, t.sometext from deleted d 
    join dbo.mytesting t on t.test_id = d.test_id
    
    Delete dbo.mytesting where test_id in (select test_id from deleted)
    go
    
    delete dbo.mytesting where test_id = 1
    select * from dbo.mytesting
    select * from dbo.myaudit 
    Go 
    
    drop table dbo.mytesting
    drop table dbo.myaudit
    

    如果您可以将字段更改为 varchar(max) 或 nvarchar(max) ,那是最好的解决方案。 Text 和 ntext 已弃用,应在下一版本的 SQL Server 中完全删除。

    【讨论】:

      【解决方案3】:

      使用 After Trigger 可能会更好。不太复杂。

      如果你有以下表格

      CREATE TABLE [dbo].[Data](
      [DocumentID] [smallint] NULL,
      [Data] [nvarchar](max) NULL
      ) 
      

      CREATE TABLE [dbo].[Audit](
      [DocumentID] [smallint] NULL,
      [Data] [nvarchar](max) NULL
      ) 
      

      每当从数据表中删除一行时,以下 After 触发器应在审计表中插入一行

      Create Trigger audit_Table_Deletes on dbo.Data for delete 
      as
      if @@rowcount = 0 return;
      Insert into audit (DocumentID, Data) Select DocumentID, Data from deleted;
      Go
      

      【讨论】:

      • 唯一的问题是无法从已删除的表中插入文本字段。
      • “不能在 'inserted' 和 'deleted' 表中使用 text、ntext 或 image 列。”
      • 您可以将文本数据转换为 nvarchar(max) 吗?根据此technet.microsoft.com/en-us/library/bb510662.aspx,看起来不推荐使用 text ntext 和 image 数据类型
      • 我一直在将我所有的 text/ntext 列转换为 nvarchar(max) 并且从未如此快乐。
      【解决方案4】:

      我曾经需要捕获正在被删除的记录;我写了一个触发器,它将记录复制到与第一个具有相同结构的不同表中:它是这样的:

      create trigger [delta_del] on [customer]
      for delete
      as
      
      declare <variables> from deleted;
      open mycurs
      fetch next from mycurs into @v1, @v2
      while (@@fetch_status = 0
      begin
      insert into delta (fields) values (@v1, @v2)
      fetch next from mycursor into @v1, @v2
      end
      
      close mycursor
      deallocate mycursor
      
      etc.
      

      【讨论】:

      • @brismith,光标仅作为最后的手段!您可以将光标替换为:insert into delta (...fields...) SELECT ...fields... from deleted 它为从选择返回的每一行插入一行。但是,这将与 OP 提到的已弃用的 TEXT 数据类型存在问题。
      • 感谢您的提示!我以为我必须逐个记录地遍历批处理,将记录复制到新表中
      猜你喜欢
      • 2015-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多