Joh*_*hnG 7 trigger sql-server dynamic-sql sql-clr
在触发器中,我试图创建一个唯一的表名(使用NEWID()),我可以存储在插入和删除的表中找到的数据。
Declare @NewID varchar(50) = Replace(convert(Varchar(50),NEWID()),'-','')
Declare @SQLStr varchar(8000)
Set @SQLStr= 'Select * into [TMPIns' + @newID + '] from inserted'
Exec (@SQLStr)
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:无效的对象名称“插入”
我知道我可以做到:
Select * into #inserted from inserted
Set @SQLStr= 'Select * into [TMPIns' + @newID + '] from #inserted'
Exec (@SQLStr)
Run Code Online (Sandbox Code Playgroud)
但是我不想使用 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 可以创建的最无用的东西。然而,我们这里有一个他们非常适合的场景。从 SQLCLR 代码提交的 SQL 是动态 SQL。并且 SQLCLR 触发器可以访问inserted和deleted表,因此看起来 SQLCLR 触发器可以访问动态 SQL 中的inserted和表。deleted下面是完成此请求的代码(请注意,数据库连接正在使用进程内“上下文连接”,因此可以用 标记程序集PERMISSION_SET = SAFE;无需非对称密钥或将数据库设置为TRUSTWORTHY ON):
要创建触发器的测试表(如果使用 Visual Studio / SSDT,表定义必须包含在项目中):
CREATE TABLE TableThatHasTriggers
(
TableThatHasTriggersID INT IDENTITY(1, 1) NOT NULL
CONSTRAINT [PK_TableThatHasTriggers] PRIMARY KEY,
InsertTime DATETIME NOT NULL
CONSTRAINT [DF_TableThatHasTriggers_InsertTime] DEFAULT (GETDATE()),
SomeValue NVARCHAR(50) COLLATE Latin1_General_100_CI_AS NULL
);
Run Code Online (Sandbox Code Playgroud)
SQLCLR C# 代码:
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
public class Triggers
{
[SqlTrigger(Target = "TableThatHasTriggers", Event = "FOR INSERT, UPDATE")]
public static void tr_TableThatHasTriggers_audit()
{
string _AuditSQL = @"
SELECT ins.*
INTO dbo.[TMPIns_" + Guid.NewGuid().ToString().Replace("-", "") + @"]
FROM INSERTED ins;
";
SqlConnection _Connection = new SqlConnection("Context Connection = true");
SqlCommand _Command = _Connection.CreateCommand();
_Command.CommandText = _AuditSQL;
// SqlContext.Pipe.Send(_AuditSQL); // display query for debugging purposes ONLY
try
{
_Connection.Open();
_Command.ExecuteNonQuery();
}
finally
{
_Command.Dispose();
_Connection.Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)
将 SQLCLR 触发器放置到表上的 T-SQL 包装器对象:
using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
public class Triggers
{
[SqlTrigger(Target = "TableThatHasTriggers", Event = "FOR INSERT, UPDATE")]
public static void tr_TableThatHasTriggers_audit()
{
string _AuditSQL = @"
SELECT ins.*
INTO dbo.[TMPIns_" + Guid.NewGuid().ToString().Replace("-", "") + @"]
FROM INSERTED ins;
";
SqlConnection _Connection = new SqlConnection("Context Connection = true");
SqlCommand _Command = _Connection.CreateCommand();
_Command.CommandText = _AuditSQL;
// SqlContext.Pipe.Send(_AuditSQL); // display query for debugging purposes ONLY
try
{
_Connection.Open();
_Command.ExecuteNonQuery();
}
finally
{
_Command.Dispose();
_Connection.Dispose();
}
}
}
Run Code Online (Sandbox Code Playgroud)