【问题标题】:How to fix the error procedure expects parameter '@parameters' of type 'ntext/nchar/nvarchar'?如何修复错误过程需要'ntext/nchar/nvarchar'类型的参数'@parameters'?
【发布时间】:2011-08-01 21:04:43
【问题描述】:

我正在尝试使用存储过程来显示表的结果、关联的表或数据库的最新更改。存储过程是:

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 

除了 select 语句的结果之外,它还应该返回项目。存储过程没有输入。存储过程在 SQL Management Studio (2008) 中编译良好,但页面返回错误: Microsoft OLE DB Provider for SQL Server 错误“80040e14”

过程需要“ntext/nchar/nvarchar”类型的参数“@parameters”。 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 代码中。对于我的一生,我无法确定为什么会产生这个错误。

【问题讨论】:

  • 检查你是否有相同的 SP 但有另一个参数列表(见不在 dbo 模式中)
  • 另一条评论 - 如果在您的 WHERE 子句时间范围内的 MKTG_Recent 中更新了多个表,您知道您将获得哪个表吗?我当然不会。

标签: sql sql-server stored-procedures asp-classic


【解决方案1】:

在这个答案中,我将尝试重现您在问题中提到的问题,并解释我是如何解决这个问题的。

首先,让我们使用 Create Tables Script 部分下的脚本创建两个名为 dbo.MKTG_Recentdbo.Table_1 的表。我根据我使用问题中提供的数据所做的一些假设创建了这些表。使用该脚本,表 dbo.MKTG_Recent 将填充 1 条记录。

接下来,使用创建存储过程脚本部分下提供的脚本创建名为dbo.MKTG_Current的存储过程。

如果我们尝试使用EXEC MKTG_Current null, null的EXEC命令执行存储过程,则会抛出错误消息Msg 214, Level 16, State 3, Procedure sp_executesql, Line 1 Procedure expects parameter '@parameters' of type 'ntext/nchar/nvarchar'.。参考截图#1

在阅读MSDNsp_executesql的使用方法后,我发现存储过程的第二个参数定义了输出参数的类型,它必须是一个Unicode字符串。因此,我修改了存储过程,将第二个参数提供为 Unicode 字符串,并以 N 为前缀。请参阅屏幕截图 #2 了解存储过程的更改。

屏幕截图#3 显示了更改后存储过程dbo.MKTG_Current 的输出。存储过程将产生两个输出。一个用于传递给 sp_executesql 的变量 @Bork 中的查询语句,另一个输出对应于显示 OUTPUT 变量的 SELECT 语句。

根据需求,我不确定你是否甚至需要调用 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:执行显示错误信息

#2:对存储过程的更改

#3:修改后的存储过程输出

#4:简化的存储过程输出

【讨论】:

    【解决方案2】:

    您将@Bork 声明为NVARCHAR。那你为什么说:

    SET @Bork = 'SELECT ...';
    

    ?应该是:

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

    这就是我们定义NVARCHAR (Unicode) 字符串的方式。 N代表国家。如果你忽略那个 N 前缀,sp_executesql 会假定它是VARCHAR,这会导致错误。

    编辑为基伦

    虽然技术上是的,但您可以声明 NVARCHAR 不带 N 前缀的文字,但有几个原因可以说明您永远不应该这样做。一是避免 user873479 收到的错误。其他是为了确保正确的结果。一些例子:

    (A) 让我们试试sp_executesql 带N 前缀和不带N 前缀。即使字符串中没有实际的 Unicode 字符,在调用 sp_executesql 时忘记输入 N 前缀也会导致与此问题完全相同的错误:

    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 之间隐式切换可以将搜索变成扫描,但我认为现在错误消息和不正确的结果应该足够了。

    当然,您可以在不使用 N 前缀的情况下声明 NVARCHAR 字面量,但前提是您不调用期望 NVARCHAR 的过程,并且前提是您的数据实际上不包含任何 Unicode 字符(在这种情况下,我不得不想知道你为什么首先要使用NVARCHAR)。

    【讨论】:

    • 这不是真的,你可以使用没有 N 的文字就可以使用 NVARCHAR 类型
    • 好的@Kieren,你试过打电话给EXEC sp_executesql 'SELECT 1';了吗?对于用户收到描述的错误消息的原因,您有更好的答案吗?也许您可以阅读我更新的答案并重新考虑您的反对意见。
    • create procedure proc_ParamTest(@p1 nvarchar(200)) as select @p1 go / proc_ParamTest 'Hello' 在这里工作得很好。 sp_helptext 'sp_executesql' 也告诉我 executesql 是 'Internal' 所以可能是一个特例?甚至sp_helptext 告诉我它自己需要一个nvarchar 参数并接受我的字面意思。我没有更好的主意,不。但是 OP 也没有使用 varchar 文字调用 sp_executesql
    • 用户不是在调用 sp_helptext,而是在调用 sp_executesql。是的,这是一个特例,但是您是否阅读了我编辑的其余答案?您是否尝试将一些实际的 Unicode 数据传递给您的 proc_ParamTest?
    • 是的,我确实读过它,我会再说一遍,你必须为文字加上 N 前缀是不正确的。如果文字包含 unicode 字符,则需要添加前缀,但这不是问题所在吗?他们正在调用 sp_executesql 并将其传递给 nvarchar 参数,而不是文字。那么这有什么关系呢?
    猜你喜欢
    • 1970-01-01
    • 2016-12-25
    • 2014-12-07
    • 2018-03-01
    • 2020-01-28
    • 1970-01-01
    • 2020-10-13
    • 2017-07-16
    相关资源
    最近更新 更多