ストアドプロシージャを使用して、テーブルの結果、および関連するテーブルまたはデータベースへの最近の変更を表示しようとしています。ストアドプロシージャは次のとおりです。
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ステートメントの結果に加えてアイテムに戻ることになっています。ストアドプロシージャへの入力はありません。ストアドプロシージャはSQLManagement Studio(2008)で正常にコンパイルされますが、ページにエラーが返されます:Microsoft OLE DB Provider for SQLServerエラー '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コードにあることを意味します。私の人生では、なぜこのエラーが発生しているのか特定できません。
この回答では、質問で言及した問題を再現し、これをどのように解決したかについても説明します。
まず、Create Tables Scriptセクションのスクリプトを使用して、dbo.MKTG_Recent
とdbo.Table_1
という名前の2つのテーブルを作成しましょう。これらのテーブルは、質問で提供されたデータを使用して作成したいくつかの仮定に基づいて作成しました。スクリプトを使用すると、テーブル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 を読んだ後、ストアドプロシージャの2番目のパラメータが次のタイプを定義していることがわかりました。出力パラメータであり、Unicode文字列である必要があります。そこで、2番目のパラメーターをUnicode文字列としてNをプレフィックスとして指定することにより、ストアドプロシージャを変更しました。ストアドプロシージャの変更については、スクリーンショット#2を参照してください。
スクリーンショット#3は、変更を加えた後のストアドプロシージャdbo.MKTG_Current
の出力を示しています。ストアドプロシージャは2つの出力を生成します。 1つはsp_executesqlに渡される変数@Borkのクエリステートメント用で、もう1つは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:簡略化されたストアドプロシージャの出力
@BorkをNVARCHAR
として宣言しました。それで、なぜあなたは言うのですか:
SET @Bork = 'SELECT ...';
?する必要があります:
SET @Bork = N'SELECT ...';
これがNVARCHAR
(Unicode)文字列の定義方法です。 Nは全国を表します。そのNプレフィックスを省略すると、sp_executesql
はそれがVARCHAR
であると見なし、エラーが発生します。
[〜#〜] edit [〜#〜]キーレンの場合
技術的にはそうですが、[〜#〜] can [〜#〜]NプレフィックスなしでNVARCHAR
リテラルを宣言できますが、いくつかあります絶対にそうすべきではない理由。 1つは、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
を使用するのが面倒なのか疑問に思う必要があります)。