在触发器中,我试图创建一个唯一的表名(使用NEWID()
),我可以存储在插入和删除的表中找到的数据。
Declare @NewID varchar(50) = Replace(convert(Varchar(50),NEWID()),'-','')
Declare @SQLStr varchar(8000)
Set @SQLStr= 'Select * into [TMPIns' + @newID + '] from inserted'
Exec (@SQLStr)
我收到以下错误:无效的对象名称“已插入”
我知道我可以做到:
Select * into #inserted from inserted
Set @SQLStr= 'Select * into [TMPIns' + @newID + '] from #inserted'
Exec (@SQLStr)
但我不想使用 TempDB,因为这些表可能会变得很大,而且我也觉得它是多余的。有没有办法避免创建#inserted?
如果没有更深入地了解此请求的预期目标,似乎即使解决了这个直接问题,工作代码也可能无法提供任何真正有用的东西。一些担忧是:
UpdatedDate
或某个日期字段吗?如果不是,不看表创建日期就没有年代感。UPDATE
,则需要同时捕获inserted
和deleted
表。但是,如果它们具有基于 GUID 的名称,那么您将无法关联特定 UPDATE 操作的“插入”和“删除”复制表。您必须重新使用相同的 GUID 值并在表名前缀中表示“插入”或“删除”。如果您没有动态创建表,那么您可以包含一个指定 DML 操作的列,将表inserted
和deleted
表都转储到已经存在的表中,并且只需使用序列中的 GUID 或 INT 来关联同一UPDATE
操作的 2 行.然而,话虽如此,通过动态 SQL
inserted
与表交互的问题是一个有趣的问题。deleted
不幸的是,它不能在 T-SQL 中完成。所以现在这也是一个挑战:-)。幸运的是,这实际上是可以做到的。怎么会这样?在我们的朋友 SQLCLR 先生的帮助下。现在,似乎没有很多情况真正需要,甚至受益于 SQLCLR 触发器。它们似乎是您可以使用 SQLCLR 创建的最没用的东西。但是,在这里我们有一个场景,它们非常适合。从 SQLCLR 代码提交的 SQL 是动态 SQL。并且 SQLCLR 触发器可以访问
inserted
和deleted
表,因此 SQLCLR 触发器似乎可以访问动态 SQL 中的inserted
和表。deleted
下面是完成此请求的代码(请注意,数据库连接正在使用进程内“上下文连接”,因此程序集可以标记为PERMISSION_SET = SAFE
;不需要非对称密钥或将数据库设置为TRUSTWORTHY ON
):要在其上创建触发器的测试表(如果使用 Visual Studio / SSDT,则表定义必须包含在项目中):
SQLCLR C# 代码:
将 SQLCLR 触发器放置到表上的 T-SQL 包装器对象:
(若干年后……)
实际上,线程标题描述的可以在您明智地使用游标进行插入的处理的条件下使用T-SQL完成。
即:允许创建一个访问 [Inserted] 的游标,然后将该名称传递给动态代码。您甚至可以让动态 sql 执行所有打开、同时、获取、关闭和解除分配的操作。
因此,在来自 OP 的示例中,这并不好,但在更复杂的触发器遍历插入的一个一个来做事情的情况下,这可能是一个非常真实的解决方案。