bdu*_*kes 13 sql-server dynamic-sql sp-executesql
我正在尝试动态创建触发器,但在使用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
Run Code Online (Sandbox Code Playgroud)
但是,我希望能够@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
Run Code Online (Sandbox Code Playgroud)
运行上面的代码时,我收到一个错误:
Msg 156,Level 15,State 1,Line 2
关键字'TRIGGER'附近的语法不正确.
在尝试了几件事之后,我发现即使我根本不使用@tableName动态SQL,我仍然会遇到这个错误.我也试图创建一个错误PROCEDURE(显然,除了关键字'PROCEDURE'附近的消息是不正确的语法.)
由于SQL直接或不提供参数时运行正常sp_executesql,这似乎我在SQL引擎中遇到了一个真正的限制,但我没有看到它记录在任何地方.有没有人知道是否有办法接受动态CREATE脚本,或至少了解正在遇到的潜在限制?
更新
我可以添加一个PRINT语句,并获得以下有效的SQL,并成功运行(直接运行时).如果SQL中没有任何动态(它只是一个没有连接的单个字符串),我仍然会收到错误.
CREATE TRIGGER TR_ContentItems ON ContentItems FOR INSERT
AS
BEGIN
PRINT @tableName
END
Run Code Online (Sandbox Code Playgroud)
无论是使用sysname还是nvarchar(max)参数,我也会得到相同的错误.
我强烈警告不要将动态 SQL 与表名一起使用。您正在为自己设置一些严重的 SQL 注入问题。您应该验证进入的任何内容@tableName。
也就是说,在你的例子中......
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
Run Code Online (Sandbox Code Playgroud)
...您试图将您声明的内容输入@tableName到您正在为其创建的文本中@sql,然后您尝试通过 传递参数spexecutesql。这使得你@sql在尝试调用它时无效。
你可以试试:
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
Run Code Online (Sandbox Code Playgroud)
...这会给你字符串...
'
CREATE TRIGGER TR_' + @tableName + N' ON ' + @tableName + N' FOR INSERT
AS
BEGIN
PRINT @tableName
END'
Run Code Online (Sandbox Code Playgroud)
...然后它可以接受您传递的参数...
EXEC sp_executesql @sql, N'@tableName sysname', @tableName=@tableName ;
Run Code Online (Sandbox Code Playgroud)
同样,在将任何内容传递到将使用动态表名称的动态 SQL 之前,我会使用一些严格的验证(和白名单)。
注意:如下所述,我相信您可以使用 执行的 DML 语句受到限制sp_executesql(),并且我认为参数化也受到限制。根据您的其他评论,听起来您并不真正需要一个动态过程,而是一种对少数元素重复特定任务的方法。如果是这种情况,我的建议是通过复制/粘贴手动执行此操作,然后执行语句。
| 归档时间: |
|
| 查看次数: |
428 次 |
| 最近记录: |