【问题标题】:Change dynamic SQL from using Exec to sp_executesql将动态 SQL 从使用 Exec 更改为 sp_executesql
【发布时间】:2014-07-08 20:19:12
【问题描述】:

我是 SQL 和特别是动态 sql 执行的初学者。

我正在尝试将存储过程中的一些动态 sql 从使用 EXEC 转换为使用 sp_executesql。

我的问题是我不知道表示多行动态 sql 的确切规则是什么。现有代码的形式为:

 Set @cmd = 'WITH vdate AS' + char(13)
           +' (SELECT valueID,' + char(13)
           +'username)' +char(13)
 +'FROM dbo.table1' + char(13)
 +'WHERE username = ''' + convert(varchar(11), @username, 106) + ''' AND' + char(13)
 Exec (@cmd)

以上只是它的外观的一个sn-p。有更多的行和更复杂的事情发生。

我现在希望能够使用 sp_executesql 方式执行此代码,因为我想将用户名属性更改为接受多个用户名的表。 请你能告诉我这个语法是什么以及我如何在最后一次工作之前制作这条线?

我已经看到代码看起来非常相似,所以我将每行开头的 +' 更改为 N' 并编译了代码,但是当我尝试在我的应用程序中使用查询时它没有执行.

谢谢,杰特诺。

【问题讨论】:

标签: sql sql-server dynamic-sql


【解决方案1】:

唯一的区别是您将使用EXEC sp_executesql @cmd 而不是EXEC (@cmd)。从技术上讲,sp_executesql 接受 NVARCHAR 参数。为了创建一个NVARCHAR 字符串,您应该 在字符串前面加上N,如下所示:

DECLARE @cmd NVARCHAR(1000);
SET @cmd = N'My string'

这表示该字符串是一个可能包含国家字符集的 Unicode 字符串。当然,您可以省略N,但如果其中包含 ASCII 字符以外的任何其他字符,那么它将无法正常工作,您最终会得到包含大量问号而不是特殊字符的字符串(CJK -中文、日文、韩文 - 例如字符集),所以最好在 NVARCHAR 字符串前加上 N

您的一些困惑是因为您将字符串连接运算符+ 替换为国家字符集标识符N。你将需要两者。在代码中包含适当的间距总是值得的,尤其是在动态 SQL 中,因为它更易于阅读。我的偏好是尽可能在行尾添加空格,但这只是我个人的偏好。此外,除非您真的想以某种方式将其打印出来,否则请删除 CHAR(13) 的东西。您的示例将变为:

DECLARE @cmd NVARCHAR(1000)    --Note this is NVARCHAR, not VARCHAR.
SET @cmd = N'WITH vdate AS '
           + N'(SELECT valueID, '
           + N'username) '
 + N'FROM dbo.table1 ' 
 + N'WHERE username = ''' + convert(NVARCHAR(11), @username, 106) + ''' AND ' --Note that you are missing a chunk here - AND what?
 EXEC sp_executesql @cmd

请注意,您的 CONVERT 不正确:首先您应该转换为 NVARCHAR(如果 @username 还没有),其次 106 部分什么都不做 - 那是日期格式。你也错过了声明的结尾,因为有一个AND,然后什么都没有。使用PRINT @cmd 来查看您生成的SQL 是否有效总是好的(它将输出@cmd 的内容,然后您可以将其复制并粘贴到SSMS 中的工作表中)。

现在,您可能希望在动态 SQL 中也有输出参数,这没问题。

DECLARE @ID INT;
DECLARE @outputValue NVARCHAR(50);
DECLARE @cmd NVARCHAR(1000);
SET @cmd = N'SELECT @value = Value FROM MyTable WHERE ID = ' + 
               CAST(@ID AS NVARCHAR(5));
EXEC sp_executesql @cmd, '@value NVARCHAR(50) OUT', @outputValue OUT;
SELECT @outputValue;

传统上,想要使用sp_executesql 而不是仅仅使用EXEC 的主要原因是您有更好的机会缓存执行计划,因此以后可以重新使用。我承认我不确定这是否仍然正确,但sp_executesql 通常是执行动态 SQL 的首选方法。很多人对动态 SQL 有一种本能的憎恨,但坦率地说,就像所有事物一样,只要它不被滥用和在不需要的地方使用,它就有它的用途。

【讨论】:

  • 非常感谢您的全面回答。我将继续更改代码,看看我是否可以让它工作。我的主要困惑是我认为与用于包含动态 sql 的语法有关。动态 SQL 是解决我正在处理的问题的最佳选择,是的,我对 + 和 N 之间的区别感到困惑。
  • 动态 SQL 和任何其他字符串之间没有区别 - ALL NVARCHAR 字符串实际上应该以 N 为前缀,无论它们包含什么。与任何语言一样,您应该始终注意函数参数的数据类型,并确保提供正确类型的数据。事实上,您可以避免很多隐式转换,但它们可能会给您带来难以追踪的问题,因此始终值得明确地进行 CASTCONVERTed 转换。
  • 不用担心,很乐意为您提供帮助。动态 SQL 在我刚开始的时候把我搞糊涂了。
猜你喜欢
  • 2010-10-07
  • 2023-03-25
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 2013-01-07
  • 2011-10-09
  • 1970-01-01
  • 2020-07-05
相关资源
最近更新 更多