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 在触发器中使用临时表的主要内容,如果未能解决你的问题,请参考以下文章

视图触发器事务存储过程函数

nysql之视图触发器事务

十mysql之视图,触发器,事务等

Mysql:视图触发器事务存储过程函数

Mysql 临时表 视图

Mysql之视图 触发器 事务 存储过程 函数