我正在尝试创建一个审核触发器,而不必多次指定列列表。
为此,我想在触发器中生成INSERTED或DELETED数据内容的临时表,然后将其处理到审计表中。
如果我使用它:
IF @ChangeType = 'D'
SELECT * INTO #tmp FROM DELETED
ELSE
SELECT * INTO #tmp FROM INSERTED
然后我在第二个SELECT * INTO中得到一个编译错误,表#tmp已经存在。
如果我尝试使用动态SQL解决此问题:
SET @Sql = 'SELECT * INTO #tmp FROM '
IF @ChangeType = 'D'
SET @Sql = @Sq + 'DELETED'
ELSE
SET @Sql = @Sql + 'INSERTED'
EXEC (@Sql)
然后我收到DELETED和INSERTED表不存在的错误。
如何将触发器中的INSERTED和DELETED表转换为临时表或其他内存表?
答案 0 :(得分:4)
尝试在if
之外创建临时表,例如:
SELECT TOP 0 * INTO #tmp FROM DELETED
IF @ChangeType = 'D'
INSERT INTO #tmp SELECT * FROM DELETED
ELSE
INSERT INTO #tmp SELECT * FROM INSERTED
答案 1 :(得分:1)
由于临时表对象的解析解析,这是一个已知问题。在同一范围内有两个SELECT-INTO语句,SQL Server就是这样做的。
SELECT * INTO #tmp FROM DELETED WHERE 1=0
IF @ChangeType = 'D'
INSERT #tmp SELECT * FROM DELETED
ELSE
INSERT #tmp SELECT * FROM INSERTED
答案 2 :(得分:0)
我很感兴趣为什么你需要首先将数据复制到另一个表中。但是,那是偏离主题的......
临时表(#temp)在逻辑上存储在光盘上,而表变量(@temp)在逻辑上仅在内存中,对于小任务可能更为理想。 (假设写入表通常只会影响少量行。)
但是,可以使用SELECT INTO技巧创建临时表,从而无需事先知道表定义。
但是,如果您事先知道了表格定义,那么您不能简单地使用以下内容吗?
DECLARE @temp TABLE (id AS INT, val as INT)
IF @ChangeType = 'D'
INSERT INTO @temp SELECT * FROM DELETED
ELSE
INSERT INTO @temp SELECT * FROM INSERTED
就个人而言,如果可能,我甚至会避免使用*。您的后续查询将仅使用特定字段,因此我只复制我正在使用的字段。这样做的另一个好处是,如果将字段添加到表中,则代码不会中断...
DECLARE @temp TABLE (id AS INT, val as INT)
IF @ChangeType = 'D'
INSERT INTO @temp SELECT id, val FROM DELETED
ELSE
INSERT INTO @temp SELECT id, val FROM INSERTED
在我看来,指定字段(这是您希望避免的)的优点是,您可以确保始终只复制您需要的字段。