SQL触发器不能执行INSTEAD OF DELETE,但是对于ntext,image列是必需的

时间:2012-02-01 19:26:21

标签: sql sql-server-2008

CREATE TRIGGER [dbo].[C1_Deletions] ON [dbo].[C1] INSTEAD OF DELETE AS
SET NOCOUNT ON
  IF EXISTS ( SELECT 'True' FROM deleted JOIN C1 ON deleted.ACCOUNTNO = C1.ACCOUNTNO )
   BEGIN
    INSERT INTO [GDeletions].[dbo].[C1] SELECT * FROM deleted
    DELETE C1 FROM C1 INNER JOIN DELETED ON C1.ACCOUNTNO = DELETED.ACCOUNTNO
   END

因此,这是我尝试使用的触发器,当我通过accountno删除它时效果很好,但是当我需要通过recid(另一列)删除时,我无法使用。

如果我将INSTEAD OF更改为AFTER,我会收到有关ntext的错误,不允许使用图像列。有没有解决这个问题的方法?我不能指定删除字符串,程序本身就是我只需要触发器来获取正在删除的数据。

我遇到的另一个更大的问题是另一个存储历史记录的表,它使用与c1表匹配的accountno存储它,但是还有recid,它对每个条目都是唯一的。如果我去删除C1条目,它会使用accountno从历史记录中删除所有条目,但是如果我删除单个历史记录条目,则它将被recid删除。

3 个答案:

答案 0 :(得分:4)

您无法从INSERTED或DELETED访问TEXT,NTEXT或IMAGE字段。但是,您可以通过与INSERTED连接从基表访问它们。这仅适用于INSERT和UPDATE,因为在DELETE中,基行不再存在。

要实现所需,在另一个触发器中,将主键和TEXT,NTEXT和IMAGE列复制到边表。

例如

create table C1(
   accountNo int identity primary key,
   someColumn nvarchar(10),
   someNtext ntext
)

create table C1_side(
   accountNo int primary key,
   someNtext ntext
)

create trigger trgC1_IU  on C1 AFTER INSERT, UPDATE
as
BEGIN
   -- Ensure side row exists
   insert C1_side(accountNo, someNtext)
   select accountNo from INSERTEd
   where not exists (select 1 from C1_side where C1_side.accountNo = inserted.accountNo)

   -- Copy NTEXT value to side row
   update C1_side
   set someNtext = c1.someNtext
   from C1_side inner join C1 on C1_side.accountNo = C1.accountNo
   inner join INSERTED on INSERTED.accountNo = C1.accountNo
   -- Could improve by checking if the column was updated for efficiency

END

现在,在DELETE触发器中,您可以将DELETED连接到C1_side以读取ntext列的先前值。请注意,对于已存在于C1中的行,您必须填充边表的初始值。

答案 1 :(得分:3)

停止使用ntext和image:they are deprecated。请改用nvarchar(max)和varbinary(max)。与不推荐使用的数据类型不同,它们的行为类似于普通数据类型。

答案 2 :(得分:0)

我发现,即使您一次删除多行,在查询执行期间每行仍然会被放入DELETED临时表中,因此我的触发器会遍历每条记录并在recid上匹配(这对每个行都是唯一的)行)并从那里删除/移动。