我正在尝试创建一个使用可变数量参数的存储过程。由于我对编写存储过程和TSQL一般都很陌生,所以我决定只用一个参数来编写它。但是,当我尝试执行它时,我不断收到一条错误,指出“必须声明标量变量@FirstName”。现在,我试图将SQL语句存储在另一个变量@sql中。我的程序如下:
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))
AS
BEGIN
DECLARE @sql AS NVARCHAR(4000)
SET @sql = 'SELECT e.* from Employee e
WHERE e.FirstName = @FirstName'
EXEC (@sql)
END
我看了别的地方,试过EXEC sp_execute @sql,但是没用。奇怪的是,当我不声明@sql变量而只是正常编写我的查询时,工作是什么。既然如此,我假设我使用SET和EXEC函数时出现了一些错误。我也不是100%确定我正在使用BEGIN和END。我理解它的方式是BEGIN和END将SQL语句分成逻辑块,因此在IF发挥作用时更常用。谁能告诉我这里的参数到底发生了什么?对于为什么SQL Server认为它没有被声明,我真的很困惑。
答案 0 :(得分:3)
变量参数必须在引号之外。
SET @sql = N'SELECT e.* from Employee e
WHERE e.FirstName = ''' + @FirstName + ''''
或者,更好的是,在没有任何动态SQL的情况下运行它。
SELECT e.*
from Employee e
WHERE e.FirstName = @FirstName
答案 1 :(得分:1)
因为
'Select ... @FirstName'
与
不同Select ... @FirstName
一个是字符串,另一个是SQL查询
你应该做的是
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))
AS
BEGIN
DECLARE @sql AS NVARCHAR(4000)
SET @sql = 'SELECT e.* from Employee e
WHERE e.FirstName = ''' + @FirstName + ''''
EXEC (@sql)
END
答案 2 :(得分:1)
执行动态sql时,您正在切换上下文,并且变量不会在上下文之间移动。一旦将SQL语句声明为字符串,就必须将everythign提供给该字符串,以便识别它。
显然,在这种情况下你不需要动态SQL,但是一旦这样做的方法是这样的:
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))
AS
BEGIN
DECLARE @sql AS NVARCHAR(4000)
SET @sql = 'SELECT e.* from Employee e
WHERE e.FirstName = @FirstName'
EXEC sp_executeSQL @sql, N'@Firstname varchar(50)', @FirstName
END
sp_executeSQL允许您声明内部参数(第二个子句),并为它们提供值(最后一个子句)。
答案 3 :(得分:0)
您需要将查询更改为以下内容,因为@Firstname变量不在范围内:
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))
AS
BEGIN
DECLARE @sql AS NVARCHAR(4000)
SET @sql = 'SELECT e.* from Employee e
WHERE e.FirstName = ''' + @FirstName + ''''
EXEC (@sql)
END
答案 4 :(得分:0)
使用此正文,无需“动态”查询
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))
AS
BEGIN
SELECT e.* from Employee e
WHERE e.FirstName = @FirstName
END
或强>
使用动态查询不将变量本身包含在脚本中 - 将它们与脚本连接起来,并且不要忘记正确引用它们。
答案 5 :(得分:0)
因为这是一个"搜索"使用可变数量的参数来查询你的行为,你需要一点一点地构建字符串 - 你需要在动态的正确行上,但你还需要避免SQL注入攻击(google) " Little Bobby Tables")。因此,您需要使用参数化动态SQL语句:
ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
@FirstName VARCHAR(50)
AS
BEGIN
DECLARE @sql AS NVARCHAR(4000)
SET @sql = 'SELECT e.* FROM Employee e WHERE 1 = 1'
IF @FirstName IS NOT NULL
BEGIN
SET @sql = @sql + ' AND FirstName = @pFirstName'
END
-- More IF statements, building up the query
EXEC sp_ExecuteSQL @sql, N'@pFirstName VARCHAR(50)', @FirstName
第二个和第三个参数将@FirstName参数映射到查询"内部"参数(我通常以' p'或'参数为前缀,只是为了区别于存储过程自己的参数)。
每次添加要搜索的新参数时,都会根据需要扩展sp_Exceute,因此您最终可能会这样做:
EXEC sp_ExecuteSQL @sql,' N'
@pFirstName VARCHAR(50),
@pSurName VARCHAR(50),
@pDateOfBirth DATETIME', @FirstName, @Surname, @DateOfBirth