Ошибка при объявлении параметра в хранимой процедуре - PullRequest
0 голосов
/ 22 декабря 2011

Я пытаюсь создать хранимую процедуру, которая использует переменное количество параметров.Поскольку я довольно плохо знаком с написанием хранимых процедур и 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 ]

3 голосов
/ 22 декабря 2011

Параметр переменной должен находиться вне кавычек.

SET @sql = N'SELECT e.* from Employee e
             WHERE e.FirstName = ''' + @FirstName + ''''

Или, что еще лучше, запустите его без какого-либо динамического SQL.

SELECT e.* 
    from Employee e
    WHERE e.FirstName = @FirstName 
1 голос
/ 22 декабря 2011

Когда вы выполняете динамический sql, вы переключаете контексты, а переменные не перемещаются между контекстами. Как только вы объявляете оператор 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 sp_executeSQL @sql, N'@Firstname varchar(50)', @FirstName
   END

sp_executeSQL позволяет объявлять внутренние параметры (второе предложение) и предоставлять им значения (последнее предложение).

1 голос
/ 22 декабря 2011

Потому что

'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
0 голосов
/ 22 декабря 2011

Поскольку это запрос типа «поиск», который вы выполняете с переменным числом параметров, вам нужно постепенно наращивать строку - вы находитесь на правильных линиях, что она должна быть динамической, но вы также необходимо избегать атак с использованием 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» или «param», чтобы отличить их от собственных параметров хранимой процедуры).

Вы расширяете sp_Exceute соответствующим образом каждый раз, когда добавляете новый параметр для поиска, поэтому вы можете в конечном итоге выполнить:

    EXEC sp_ExecuteSQL @sql,' N'
              @pFirstName   VARCHAR(50),
              @pSurName     VARCHAR(50),
              @pDateOfBirth DATETIME', @FirstName, @Surname, @DateOfBirth
0 голосов
/ 22 декабря 2011

Использовать это тело, без "динамического" запроса

ALTER PROCEDURE [dbo].[GetEmployeeByParameters]
(@FirstName varchar(50))

AS

BEGIN

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

OR

при использовании динамического запроса сами не включайте переменные в сценарий - объедините их с помощью сценария и не забудьте правильно их заключить в кавычки .

0 голосов
/ 22 декабря 2011

Вам необходимо изменить свой запрос на следующий, поскольку переменная @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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...