Как исправить ошибку, процедура ожидает параметр '@parameters' типа 'ntext / nchar / nvarchar'? - PullRequest
9 голосов
/ 02 августа 2011

Я пытаюсь использовать хранимую процедуру для отображения результатов таблицы и связанной таблицы или недавних изменений в базе данных. Хранимая процедура:

set ANSI_NULLS ON
set NOCOUNT ON
set QUOTED_IDENTIFIER ON
go


ALTER PROCEDURE [dbo].[MKTG_Current]( @added smalldatetime OUTPUT, @named varchar(50) OUTPUT)
AS

DECLARE @pDate smalldatetime;
DECLARE @AIID int;
DECLARE @Table varchar(50);
DECLARE @Bork nvarchar(350);
SET @pDate = GETDATE()


SELECT @Table=[Table], @AIID=AIID, @added=date_added  FROM MKTG_Recent WHERE date_added > DATEDIFF(day, date_added, DATEADD(DD, 30, @pDate))
SET @named = @Table
SET @Bork = 'SELECT * FROM ' + QUOTENAME(@Table) + ' WHERE AIID= ' + cast(@AIID as varchar(100))

EXECUTE sp_executesql @Bork, @added OUTPUT, @named OUTPUT


SELECT @added, @named 

Он должен возвращаться к элементам в дополнение к результатам из оператора выбора. Нет входных данных для хранимой процедуры. Хранимая процедура прекрасно компилируется в SQL Management Studio (2008), но страница возвращает ошибку: Поставщик Microsoft OLE DB для SQL Server, ошибка «80040e14»

Процедура ожидает параметр '@parameters' типа 'ntext / nchar / nvarchar'. index.asp, строка 61

Строка 61 страницы выделена жирным шрифтом:

  dim Objrs, cmd
  set Objrs = Server.CreateObject("ADODB.RecordSet")
  set cmd = Server.CreateObject("ADODB.Command")
  set conn = Server.CreateObject("ADODB.Connection")
  conn.Open strConnect
  set cmd.ActiveConnection = conn
  cmd.CommandText="MKTG_Current"
  cmd.CommandType=adCmdStoredProc
  cmd.Parameters.Append cmd.CreateParameter("@added", 135, 2)
  cmd.Parameters.Append cmd.CreateParameter("@named", 200, 2, 50)
Line 61 **set Objrs = cmd.Execute**
  name_of_table = cmd.Parameters("@named")
  added = cmd.Parameters("@added")  

У меня сложилось впечатление, что это вызвано ошибкой кода SQL, но я ее не вижу. Быстрая проверка Objrs.state возвращает 0, что означает, что проблема определенно заключается в коде SQL. На всю жизнь я не могу понять, почему генерируется эта ошибка.

Ответы [ 2 ]

15 голосов
/ 02 августа 2011

В этом ответе я попытаюсь воссоздать проблему, о которой вы упоминали в вопросе, а также объясню, как я решил эту проблему.

Сначала давайте создадим две таблицы с именами dbo.MKTG_Recent и dbo.Table_1, используя сценарии в разделе Создать сценарий таблиц . Я создал эти таблицы на основе некоторых предположений, которые я сделал, используя данные, представленные в вопросе. Используя скрипт, таблица dbo.MKTG_Recent будет заполнена 1 записью.

Затем создайте хранимую процедуру с именем dbo.MKTG_Current, используя сценарий, предоставленный в разделе Создать сценарий хранимой процедуры раздел.

Если мы попытаемся выполнить хранимую процедуру командой EXEC как EXEC MKTG_Current null, null, будет выдано сообщение об ошибке Msg 214, Level 16, State 3, Procedure sp_executesql, Line 1 Procedure expects parameter '@parameters' of type 'ntext/nchar/nvarchar'.. Смотрите скриншот # 1

После прочтения MSDN об использовании процедуры sp_executesql я обнаружил, что второй параметр хранимой процедуры определяет типы выходных параметров, и он должен быть Строка Юникода. Итак, я изменил хранимую процедуру, предоставив второй параметр в виде строки Unicode с префиксом N. Смотрите скриншот # 2 для изменения хранимой процедуры.

Снимок экрана # 3 показывает вывод хранимой процедуры dbo.MKTG_Current после внесения изменений. Хранимая процедура выдаст два выхода. Один для оператора запроса в переменной @Bork, который передается в sp_executesql, а другой вывод соответствует оператору SELECT, который отображает переменные OUTPUT.

Исходя из требования, я не уверен, что если вам даже нужно вызвать sp_executesql, вы можете написать хранимую процедуру, как показано в разделе Упрощенная хранимая процедура . Я могу ошибаться, потому что я не совсем понимаю требование. Снимок экрана # 4 показывает вывод упрощенной хранимой процедуры. Оператор SELECT не требуется, поскольку значения передаются через параметры OUTPUT . Я включил оператор SELECT только для отображения результатов запроса.

Надеюсь, это направит вас в правильном направлении.

Сценарий создания таблиц:

CREATE TABLE [dbo].[MKTG_Recent](
    [Table] [varchar](40) NOT NULL,
    [AIID] [int] NOT NULL,
    [date_added] [datetime] NOT NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Table_1](
    [AIID] [int] NOT NULL,
    [added] [smalldatetime] NOT NULL,
    [named] [varchar](50) NOT NULL
) ON [PRIMARY]
GO

INSERT INTO dbo.MKTG_Recent ([Table], AIID, date_added) 
VALUES ('Table_1', 1, '2011-08-01')
GO

Сценарий создания хранимой процедуры:

SET ANSI_NULLS ON
SET NOCOUNT ON
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[MKTG_Current]
(       @added  SMALLDATETIME   OUTPUT
    ,   @named  VARCHAR(50)     OUTPUT
)
AS

DECLARE @pDate  SMALLDATETIME;
DECLARE @AIID   INT;
DECLARE @Table  VARCHAR(50);
DECLARE @Bork   NVARCHAR(350);

SET     @pDate  = GETDATE()

SELECT  @Table  = [Table]
    ,   @AIID   = AIID
    ,   @added  = date_added  
FROM    dbo.MKTG_Recent 
WHERE   date_added > DATEDIFF(day, date_added, DATEADD(DD, 30, @pDate))

SET @named  = @Table
SET @Bork   = ' SELECT  * 
                FROM    ' + QUOTENAME(@Table) + ' 
                WHERE   AIID= ' + CAST(@AIID AS VARCHAR(100))

EXECUTE sp_executesql   @Bork
                    ,   @added OUTPUT
                    ,   @named OUTPUT

SELECT  @added
    ,   @named 
GO    

Упрощенная хранимая процедура:

SET ANSI_NULLS ON
SET NOCOUNT ON
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[MKTG_Current]
(       @added  SMALLDATETIME   OUTPUT
    ,   @named  VARCHAR(50)     OUTPUT
)
AS

DECLARE @Table  VARCHAR(50);

SELECT  @named  = [Table]
    ,   @added  = date_added  
FROM    dbo.MKTG_Recent 
WHERE   date_added > DATEDIFF(day, date_added, DATEADD(DD, 30, GETDATE()))

SELECT  @added AS added
    ,   @named AS named 
GO

Скриншоты:

# 1: Выполнение с сообщением об ошибке

Error_Message

# 2: Изменение внесено в хранимую процедуру

Modified_SP

# 3: Вывод хранимой процедуры после изменений

Stored_procedure_output

# 4: Упрощенный вывод хранимой процедуры

Simplified_stored_procedure_output

4 голосов
/ 02 августа 2011

Вы объявили @Bork как NVARCHAR.Так почему же вы говорите:

SET @Bork = 'SELECT ...';

?Должно быть:

SET @Bork = N'SELECT ...';

Так мы определяем NVARCHAR (Unicode) строки.N обозначает национальный.Если вы пропустите этот префикс N, sp_executesql предполагает, что это VARCHAR, и это приводит к ошибке.

EDIT для Kieren

Хотя технически да,вы CAN объявляете NVARCHAR литералы без префикса N, есть несколько причин, почему вы никогда не должны этого делать.Один из них - избежать ошибки, которую получает user873479.Другие должны обеспечить правильные результаты.Несколько примеров:

(A) Давайте попробуем sp_executesql с префиксом N и без.Несмотря на то, что в строке нет фактических символов Юникода, забывание ставить префикс N при вызове sp_executesql приводит к точно такой же ошибке, о которой этот вопрос:

EXEC sp_executesql N'SELECT 1';
EXEC sp_executesql 'SELECT 1';

Результаты

====
1
====
Msg 214, Level 16, State 2, Procedure sp_executesql, Line 1
Procedure expects parameter '@statement' of type 'ntext/nchar/nvarchar'.

(B) Теперь давайте попробуем очень простое присвоение символа Unicode переменной NVARCHAR.Обратите внимание, как без префикса N фактическое значение теряется?

DECLARE @x NVARCHAR(32) = 'Ǝ';
SELECT @x;
SET @x = N'Ǝ';
SELECT @x;

Результаты

====
?
====
Ǝ

(C) Теперь давайте сделаем еще один шаг вперед.Давайте поместим некоторые данные Unicode в таблицу:

DECLARE @foo TABLE(bar NVARCHAR(1));
INSERT @foo(bar) SELECT N'Ǝ';

-- now someone comes along looking for the row, without using N:
SELECT COUNT(*) FROM @foo WHERE bar = 'Ǝ';

Результаты

====
0

И я мог бы привести больше примеров, где неявное переключение между CHAR / VARCHAR и NCHAR / NVARCHAR может превратить поискв сканы, но я думаю, что сообщений об ошибках и неправильных результатах на данный момент должно быть достаточно.

Так что вы можете обойтись без объявления литералов NVARCHAR без использования префикса N, но только если вы не вызываетепроцедуры, которые ожидают NVARCHAR, и только если ваши данные на самом деле не содержат символов Unicode (в этом случае мне придется задуматься, почему вы вообще потрудились использовать NVARCHAR).

...