我是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)
上面只是它看起来的片段。还有更多的线条和更复杂的东西在继续。
我现在希望能够使用sp_executesql方式执行此代码,因为我想将username属性更改为接受多个用户名的表。 请您告诉我这个语法是什么,以及如何在上次工作之前完成这一行?
我看到代码看起来非常相似所以我做了什么我改变了+'成为N'在每行的开头和编译的代码但是当我尝试在我的应用程序中使用查询时它没有执行。
谢谢,Jetnor。
答案 0 :(得分:1)
唯一的区别是,您使用EXEC (@cmd)
代替EXEC sp_executesql @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中的工作中)总是好的。 / p>
现在,您可能希望在动态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有本能的仇恨,但坦率地说,就像所有事情一样,只要它没有被滥用并且在不需要它的地方使用它就会有它的用途。