在存储过程中声明参数时出错

时间:2011-12-22 15:52:16

标签: sql sql-server stored-procedures parameters

我正在尝试创建一个使用可变数量参数的存储过程。由于我对编写存储过程和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认为它没有被声明,我真的很困惑。

6 个答案:

答案 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