SQL 在触发器中使用临时表
Posted
技术标签:
【中文标题】SQL 在触发器中使用临时表【英文标题】:SQL use temporary tables in trigger 【发布时间】:2012-11-13 07:54:46 【问题描述】:我在 MSSQL Server 2008R2 中有一个触发器:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_HosFile_Delete]
ON [dbo].[hosfile] FOR DELETE
AS
insert into #pys(pyGuid)
SELECT EntryGuid AS pyGuid FROM er000 AS er
insert into t2(C1) select pyGuid from #pys
触发器执行后,t2
表为空。为什么是空的?
如果我在没有触发器的情况下执行上面的查询,t2
表就会被填满。
在触发器中使用临时表有什么问题吗?
【问题讨论】:
哪个数据库系统? SQL 是一种语言,在各种数据库系统中实现。任何你没有向我们展示的触发器。触发器在不同的数据库系统中有很大的不同。 您不会在任何地方创建表#pys
。它需要在父范围内创建。可能你得到一个对象不存在的错误。
为什么要使用临时表,而不是直接插入? INSERT INTO T2(C1) SELECT EntryGuid FROM er000
【参考方案1】:
Damien 的回答是正确的:您可以在触发器中使用临时表,但强烈建议在此处定义它们,因为触发器可以在各种上下文中触发。
如果您在触发器中使用临时表,请检查临时表是否存在,因为您无法控制上下文并且它可能已经存在:
IF OBJECT_ID('tempdb..#pys') IS NOT NULL
DROP TABLE #pys
此外,可以动态创建临时表:
SELECT * INTO #tmp
FROM inserted
当触发器包含需要访问在动态 SQL 范围内不可见的插入或删除的特殊表的动态 SQL 时,这特别有用。
避免使用##tmp(全局临时变量),因为它们是全局可见的,当多个 SPID 触发您时可能会导致问题。
【讨论】:
【参考方案2】:使用临时表没有问题,只要它们在触发器触发时在范围内。
鉴于触发器可以在任何时间、任何连接上触发,唯一有意义的范围是在触发器的主体内:
ALTER TRIGGER [dbo].[trg_HosFile_Delete]
ON [dbo].[hosfile] FOR DELETE
AS
CREATE TABLE #pys (pyGuid uniqueidentifier not null/*I'm guessing*/)
insert into #pys(pyGuid)
SELECT EntryGuid AS pyGuid FROM er000 AS er
insert into t2(C1) select pyGuid from #pys
(老实说,我不确定您是否可以从外部范围访问临时表,并且没有方便的实例来测试它。但是,即使可以,它也会非常有用脆弱的触发器)
【讨论】:
【参考方案3】:如果您使用##pys(注意双# 符号),它将在创建后全局可用。这可能对您的情况有所帮助。
【讨论】:
【参考方案4】:尝试使用 SELECT INTO 创建和填充临时表。在触发器中使用临时表时有一些限制。
【讨论】:
以上是关于SQL 在触发器中使用临时表的主要内容,如果未能解决你的问题,请参考以下文章