Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在存储过程中声明参数时出错_Sql_Sql Server_Stored Procedures_Parameters - Fatal编程技术网

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

Sql 在存储过程中声明参数时出错,sql,sql-server,stored-procedures,parameters,Sql,Sql Server,Stored Procedures,Parameters,我正在尝试创建一个使用可变数量参数的存储过程。一般来说,我对编写存储过程和TSQL非常陌生,因此我决定尝试只使用一个参数编写它。然而,当我试图执行它时,我不断收到一个错误,声明“必须声明标量变量@FirstName”。现在,我正在尝试将SQL语句存储在另一个变量@SQL中。我的程序如下所示: ALTER PROCEDURE [dbo].[GetEmployeeByParameters] (@FirstName varchar(50)) AS BEGIN DECLARE @sql A

我正在尝试创建一个使用可变数量参数的存储过程。一般来说,我对编写存储过程和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。我的理解是,开始和结束将单独的SQL语句划分为逻辑块,因此在IF发挥作用时更常用。谁能告诉我我的参数到底是怎么回事?SQL Server为什么认为它没有声明,这让我很困惑。

因为

'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
因为

'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

变量参数需要在引号之外

SET @sql = N'SELECT e.* from Employee e
             WHERE e.FirstName = ''' + @FirstName + ''''
或者,更好的做法是,在不使用任何动态SQL的情况下运行它

SELECT e.* 
    from Employee e
    WHERE e.FirstName = @FirstName 

变量参数需要在引号之外

SET @sql = N'SELECT e.* from Employee e
             WHERE e.FirstName = ''' + @FirstName + ''''
或者,更好的做法是,在不使用任何动态SQL的情况下运行它

SELECT e.* 
    from Employee e
    WHERE e.FirstName = @FirstName 

您需要将查询更改为以下内容,因为@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

您需要将查询更改为以下内容,因为@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
使用此正文,不使用“动态”查询

使用动态查询时,不要将变量本身包含在脚本中-请将它们与脚本连接起来,不要忘记正确引用它们

使用此正文,而不要使用“动态”查询


使用动态查询时,不要将变量本身包含到脚本中-一定要将它们与脚本连接起来,不要忘记正确地引用它们

当您执行动态sql时,您正在切换上下文,并且变量不会在上下文之间移动。将SQL语句声明为字符串后,必须为该字符串提供EverythSign,以便它能够识别它

显然,在这种情况下,您不需要动态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允许您声明内部参数(第二个子句),并为其提供值(最后一个子句)。

执行动态sql时,您正在切换上下文,变量不会在上下文之间移动。将SQL语句声明为字符串后,必须为该字符串提供EverythSign,以便它能够识别它

显然,在这种情况下,您不需要动态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允许您声明内部参数(第二个子句),并为其提供值(最后一个子句)。

由于这是一种“搜索”类型的查询,您需要使用数量可变的参数进行查询,因此您需要一点一点地构建字符串——您的思路正确,它需要是动态的,但您还需要避免SQL注入攻击(google“小Bobby表”)。因此,您需要使用参数化的动态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”或“param”作为前缀,以区别于存储过程自己的参数)

每次添加要搜索的新参数时,都会根据需要扩展sp_Exceute,因此可能会执行以下操作:

    EXEC sp_ExecuteSQL @sql,' N'
              @pFirstName   VARCHAR(50),
              @pSurName     VARCHAR(50),
              @pDateOfBirth DATETIME', @FirstName, @Surname, @DateOfBirth
由于这是一个“搜索”类型的查询,您需要使用数量可变的参数,因此您需要一点一点地构建字符串——这是正确的,它需要是动态的,但是您还需要避免SQL注入攻击(google的“小Bobby表”)。因此,您需要使用参数化的动态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”或“param”作为前缀,以区别于存储过程自己的参数)

每次添加要搜索的新参数时,都会根据需要扩展sp_Exceute,因此可能会执行以下操作:

    EXEC sp_ExecuteSQL @sql,' N'
              @pFirstName   VARCHAR(50),
              @pSurName     VARCHAR(50),
              @pDateOfBirth DATETIME', @FirstName, @Surname, @DateOfBirth

谢谢你,乔,这很有魅力!如果我理解正确的话,变量参数实际上需要在引号内,但不是@sql字符串的一部分?这是我能想到的关于@firstname的三重和四重单引号的唯一原因,谢谢乔,这很有魅力!如果我理解正确的话,变量参数实际上需要在引号内,但不是@sql字符串的一部分?这是我能想到的围绕@firstname的三倍和四倍单引号的唯一原因,感谢您消除了实际查询和字符串之间的差异;那有帮助!感谢您消除了实际查询和字符串之间的差异;那有帮助@Chris J-Thanx在笔记中稍微更正了一个答案bit@ChrisJ-Thanx为便条更正了一个答案Chris,这正是我所想的。我以前尝试过用IF NOT NULL语句做类似的事情,但我一直遇到“必须声明标量变量”的问题,这个问题现在已经解决了。感谢您对sp_ExecuteSQL的解释!我会使用BEGIN。。。在这种情况下,在每个IF语句中结束?你不必这样做——我这样做是出于定义性编程的习惯,因为它使IF的开始和结束更加清晰(当涉及到维护时),如果其他开发人员更改缩进或其他什么的话。关于这一主题的(许多)讨论中的一个可以是f