我正在尝试使用存储过程来显示表的结果,以及相关表或对数据库的最新更改。存储过程是:
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)中编译正常,但页面返回错误: 用于SQL Server的Microsoft OLE DB提供程序错误“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代码。对于我的生活,我无法确定为什么会产生这个错误。
答案 0 :(得分:15)
在这个答案中,我将尝试重新创建您在问题中提到的问题,并解释我是如何解决这个问题的。
首先,让我们使用创建表脚本部分下的脚本创建两个名为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前面添加第二个参数作为Unicode字符串来修改存储过程。请参阅屏幕截图#2 以获取存储过程更改。
屏幕截图#3 显示更改后存储过程dbo.MKTG_Current
的输出。存储过程将产生两个输出。一个用于变量@Bork中的查询语句,它被传递给sp_executesql,另一个输出对应于显示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:简化的存储过程输出
答案 1 :(得分:4)
您将@Bork声明为NVARCHAR
。那你为什么这么说:
SET @Bork = 'SELECT ...';
?应该是:
SET @Bork = N'SELECT ...';
这是我们定义NVARCHAR
(Unicode)字符串的方式。 N代表国家。如果您省略该N前缀,sp_executesql
会认为它是VARCHAR
,并且会导致错误。
编辑
虽然技术上是肯定的,但你 CAN 在没有N前缀的情况下声明NVARCHAR
文字,有几个原因你不应该这样做。一种是避免user873479正在接收的错误。其他人要确保正确的结果。一些例子:
(A)让我们尝试使用N前缀而不使用前缀sp_executesql
。即使字符串中没有实际的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
。)