【发布时间】:2019-06-24 02:19:11
【问题描述】:
我正在尝试动态创建触发器,但在使用 sp_executesql 并将参数传递给动态 SQL 时遇到了一个令人困惑的问题。以下简单的测试用例有效:
DECLARE @tableName sysname = 'MyTable';
DECLARE @sql nvarchar(max) = N'
CREATE TRIGGER TR_' + @tableName + N' ON ' + @tableName + N' FOR INSERT
AS
BEGIN
PRINT 1
END';
EXEC sp_executesql @sql
但是,我希望能够在脚本中使用@tableName(和其他值)作为变量,所以我将它传递给sp_executesql 调用:
DECLARE @tableName sysname = 'ContentItems';
DECLARE @sql nvarchar(max) = N'
CREATE TRIGGER TR_' + @tableName + N' ON ' + @tableName + N' FOR INSERT
AS
BEGIN
PRINT @tableName
END';
EXEC sp_executesql @sql, N'@tableName sysname', @tableName=@tableName
运行上面的时候,我得到一个错误:
消息 156,第 15 级,状态 1,第 2 行
关键字“TRIGGER”附近的语法不正确。
在尝试了几件事之后,我发现即使我在动态 SQL 中根本不使用@tableName,我仍然会收到此错误。而且我在尝试创建PROCEDURE 时也遇到此错误(显然,消息是关键字“PROCEDURE”附近的语法不正确。)
由于 SQL 直接运行或在不向 sp_executesql 提供参数时运行良好,这似乎是我在 SQL 引擎中遇到了真正的限制,但我没有看到它在任何地方记录。有谁知道是否有办法接受动态 CREATE 脚本,或者至少了解正在遇到的潜在限制?
更新
我可以添加一个PRINT 语句,并得到下面的SQL,它是有效的,并且运行成功(直接运行时)。如果 SQL 中没有任何动态内容(它只是一个没有串联的单个字符串),我仍然会收到错误。
CREATE TRIGGER TR_ContentItems ON ContentItems FOR INSERT
AS
BEGIN
PRINT @tableName
END
无论是使用sysname 还是nvarchar(max) 作为参数,我也会遇到同样的错误。
【问题讨论】:
-
使用打印语句并理解生成的语句。在执行 sp_executesql 之前打印 @sql
-
另外,您需要将@tablename 转换为nvarchar
-
可能是触发器名称已经存在。因此,在创建触发器之前尝试 DROP TRIGGER
-
@Dheerendra 从技术上讲,
sysname数据类型是nvarchar。 -
我希望能够在脚本中使用@tableName(和其他值)作为变量...在脚本中还是在触发器中?正确答案取决于此。
标签: sql-server dynamic-sql sp-executesql