プロシージャは提供されなかったパラメータを期待しています


106

SQL Serverのストアドプロシージャにアクセスするとエラーが発生する

Server Error in '/' Application.
Procedure or function 'ColumnSeek' expects parameter '@template', which was not supplied. 

これは、パラメーターを指定しても、.netのsqlへのデータ接続を介してパラメーターを指定してストアドプロシージャを呼び出すと発生(System.data.SqlClient)します。これが私のコードです。

SqlConnection sqlConn = new SqlConnection(connPath);
sqlConn.Open();

//METADATA RETRIEVAL
string sqlCommString = "QCApp.dbo.ColumnSeek";
SqlCommand metaDataComm = new SqlCommand(sqlCommString, sqlConn);
metaDataComm.CommandType = CommandType.StoredProcedure;
SqlParameter sp = metaDataComm.Parameters.Add("@template",SqlDbType.VarChar,50);
sp.Value = Template;

SqlDataReader metadr = metaDataComm.ExecuteReader();

そして私のストアドプロシージャは:

   USE [QCApp]
   GO
   SET ANSI_NULLS ON
   GO
   SET QUOTED_IDENTIFIER ON
   GO

   ALTER PROCEDURE [dbo].[ColumnSeek] 
       @template varchar(50)
   AS
   EXEC('SELECT Column_Name, Data_Type 
   FROM [QCApp].[INFORMATION_SCHEMA].[COLUMNS] 
   WHERE TABLE_NAME = ' + @template);

ここで私が間違っていることを理解しようとしています。

編集:それは結局のところ、私は、パラメータから値を取得したため、テンプレートは、URLを通過したと私は(私が使っていた渡すURLのparamを台無しにヌルだった@ため、代わりの&


非常に古い質問ですが、同じ問題が発生しました。私の場合、@ parameterの1つに余分なスペースを追加したことがわかりませんでした。1時間のデバッグ。
レオン・ペルティエ

ストアドプロシージャの実行とこのエラーの取得については、stackoverflow.com
a / 26374810/1860652を

これは、何らかの理由で今日のトップページに掲載されました。しかし、「テンプレート」の値がクライアントURLからのものである場合、これはSQLインジェクションに対して脆弱であるように思われます!少なくとも、私は使用をお勧めしますQUOTENAME(@template)
マークソウル

回答:


85

私はアプリケーションコードをチェックして、@ templateに設定している値を確認します。私はそれが無効であり、そこに問題があると思います。


ええ、テンプレートはnullでした。以前に設定するのを忘れていました。
トニーピーターソン

35
DbNullがC#の1つの最も役に立たない "機能"であることを追加できますか
thaBadDawg

295

ここに他の回答に加えて、あなたが置くことを忘れた場合:

cmd.CommandType = CommandType.StoredProcedure;

その後、このエラーも発生します。


Visual Studioからデバッグする場合:選択したデータセットの名前の横にあるレポートの[データ]タブ(レイアウトタブと[プレビュー]タブの横)に、CommandTypeを変更できる別のドロップダウンコントロールがあります。楽しい!
SarjanWebDev 2012

2
はい、SqlExceptionは奇妙です-プロシージャとして認識されていることを通知しますが、それがCommandTypeプロパティを設定して、プロシージャであることを通知する必要があります。
Tahir Hassan、

@Tahir、エラーが「プロシージャ」を一般的な用語として使用していること( "or function"の追加で示唆されているように)ではなく、意図がSQL DBストアドプロシージャであることを認識しているとは思わない。
ブライアン、

3
これは私が想像してここに来る人々の99%のための解決策です
ジョネソポリス

くそー、なぜこれほど簡単な解決策でしたか。ありがとうございました。パラメータが存在し、nullではないことを知っていたので、これですべて完了しました。
BornToDoStuff

27

この問題は確かに、通常、前述のHLGEMのようにパラメーター値をnullに設定することによって引き起こされます。私は、この問題の新しい人々の利益のために役立つとわかったこの問題のいくつかの解決策について詳しく説明すると思いました。

私が好むというソリューションは言及されたNULL(または任意の値にしたい)に、ストアドプロシージャのパラメータをデフォルトにあるsangram上記と同じですが、答えは非常に冗長であるため、見逃されることがあります。以下に沿ったもの:

CREATE PROCEDURE GetEmployeeDetails
    @DateOfBirth    DATETIME = NULL,
    @Surname        VARCHAR(20),
    @GenderCode     INT = NULL,
AS

つまり、特定の条件下でパラメーターがコードでnullに設定された場合、.NETはパラメーターを設定せず、ストアドプロシージャは定義されたデフォルト値を使用します。コードで問題を本当に解決したい場合の別の解決策は、次のような、問題を処理する拡張メソッドを使用することです。

public static SqlParameter AddParameter<T>(this SqlParameterCollection parameters, string parameterName, T value) where T : class
{
    return value == null ? parameters.AddWithValue(parameterName, DBNull.Value) : parameters.AddWithValue(parameterName, value);
}

Matt Hamiltonが、この領域を扱う際のいくつかのより優れた拡張メソッドをリストした優れた投稿を公開しています。


12

整数パラメーターに0を指定するとエラーが発生するという問題がありました。そして、それが見つかりました:

cmd.Parameters.AddWithValue("@Status", 0);

動作しますが、これは動作しません:

cmd.Parameters.Add(new SqlParameter("@Status", 0));

6
2つ目が機能しない理由は、コンパイラーがSqlParameterコンストラクターの(string、SqlDbType)オーバーロードを呼び出していると考えているためです。こちらの備考をご覧ください
Keith

1
あなたが使用したい場合はAdd、構文を、またはあなたのコマンドのオブジェクト初期化子を使用していた、あなたは名前付きパラメータを使用することができます:cmd.Parameters.Add(new SqlParameter("@Status", value: 0));
user888734

7

私の場合、DBNULL.Value定義されてnullいないが値がであるストアドプロシージャパラメータのコードから(if else条件を使用して)渡す必要がありました null


5

ストアドプロシージャの呼び出し中に同様の問題に遭遇しました

CREATE PROCEDURE UserPreference_Search
    @UserPreferencesId int,
    @SpecialOfferMails char(1),
    @NewsLetters char(1),
    @UserLoginId int,
    @Currency varchar(50)
AS
DECLARE @QueryString nvarchar(4000)

SET @QueryString = 'SELECT UserPreferencesId,SpecialOfferMails,NewsLetters,UserLoginId,Currency FROM UserPreference'
IF(@UserPreferencesId IS NOT NULL)
BEGIN
SET @QueryString = @QueryString + ' WHERE UserPreferencesId = @DummyUserPreferencesId';
END

IF(@SpecialOfferMails IS NOT NULL)
BEGIN
SET @QueryString = @QueryString + ' WHERE SpecialOfferMails = @DummySpecialOfferMails';
END

IF(@NewsLetters IS NOT NULL)
BEGIN
SET @QueryString = @QueryString + ' WHERE NewsLetters = @DummyNewsLetters';
END

IF(@UserLoginId IS NOT NULL)
BEGIN
SET @QueryString = @QueryString + ' WHERE UserLoginId = @DummyUserLoginId';
END

IF(@Currency IS NOT NULL)
BEGIN
SET @QueryString = @QueryString + ' WHERE Currency = @DummyCurrency';
END

EXECUTE SP_EXECUTESQL @QueryString
                     ,N'@DummyUserPreferencesId int, @DummySpecialOfferMails char(1), @DummyNewsLetters char(1), @DummyUserLoginId int, @DummyCurrency varchar(50)'
                     ,@DummyUserPreferencesId=@UserPreferencesId
                     ,@DummySpecialOfferMails=@SpecialOfferMails
                     ,@DummyNewsLetters=@NewsLetters
                     ,@DummyUserLoginId=@UserLoginId
                     ,@DummyCurrency=@Currency;

私が上で呼び出していた検索のためのクエリを動的に構築する方法:

public DataSet Search(int? AccessRightId, int? RoleId, int? ModuleId, char? CanAdd, char? CanEdit, char? CanDelete, DateTime? CreatedDatetime, DateTime? LastAccessDatetime, char? Deleted)
    {
        dbManager.ConnectionString = ConfigurationManager.ConnectionStrings["MSSQL"].ToString();
        DataSet ds = new DataSet();
        try
        {
            dbManager.Open();
            dbManager.CreateParameters(9);
            dbManager.AddParameters(0, "@AccessRightId", AccessRightId, ParameterDirection.Input);
            dbManager.AddParameters(1, "@RoleId", RoleId, ParameterDirection.Input);
            dbManager.AddParameters(2, "@ModuleId", ModuleId, ParameterDirection.Input);
            dbManager.AddParameters(3, "@CanAdd", CanAdd, ParameterDirection.Input);
            dbManager.AddParameters(4, "@CanEdit", CanEdit, ParameterDirection.Input);
            dbManager.AddParameters(5, "@CanDelete", CanDelete, ParameterDirection.Input);
            dbManager.AddParameters(6, "@CreatedDatetime", CreatedDatetime, ParameterDirection.Input);
            dbManager.AddParameters(7, "@LastAccessDatetime", LastAccessDatetime, ParameterDirection.Input);
            dbManager.AddParameters(8, "@Deleted", Deleted, ParameterDirection.Input);
            ds = dbManager.ExecuteDataSet(CommandType.StoredProcedure, "AccessRight_Search");
            return ds;
        }
        catch (Exception ex)
        {
        }
        finally
        {
            dbManager.Dispose();
        }
        return ds;
    }

次に、頭をひっかいた後、ストアドプロシージャを次のように変更しました。

ALTER PROCEDURE [dbo].[AccessRight_Search]
    @AccessRightId int=null,
    @RoleId int=null,
    @ModuleId int=null,
    @CanAdd char(1)=null,
    @CanEdit char(1)=null,
    @CanDelete char(1)=null,
    @CreatedDatetime datetime=null,
    @LastAccessDatetime datetime=null,
    @Deleted char(1)=null
AS
DECLARE @QueryString nvarchar(4000)
DECLARE @HasWhere bit
SET @HasWhere=0

SET @QueryString = 'SELECT a.AccessRightId, a.RoleId,a.ModuleId, a.CanAdd, a.CanEdit, a.CanDelete, a.CreatedDatetime, a.LastAccessDatetime, a.Deleted, b.RoleName, c.ModuleName FROM AccessRight a, Role b, Module c WHERE a.RoleId = b.RoleId AND a.ModuleId = c.ModuleId'

SET @HasWhere=1;

IF(@AccessRightId IS NOT NULL)
    BEGIN
        IF(@HasWhere=0) 
            BEGIN
                SET @QueryString = @QueryString + ' WHERE a.AccessRightId = @DummyAccessRightId';
                SET @HasWhere=1;
            END
        ELSE                SET @QueryString = @QueryString + ' AND a.AccessRightId = @DummyAccessRightId';
    END

IF(@RoleId IS NOT NULL)
    BEGIN
        IF(@HasWhere=0)
            BEGIN   
                SET @QueryString = @QueryString + ' WHERE a.RoleId = @DummyRoleId';
                SET @HasWhere=1;
            END
        ELSE            SET @QueryString = @QueryString + ' AND a.RoleId = @DummyRoleId';
    END

IF(@ModuleId IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
            BEGIN   
                SET @QueryString = @QueryString + ' WHERE a.ModuleId = @DummyModuleId';
                SET @HasWhere=1;
            END
    ELSE SET @QueryString = @QueryString + ' AND a.ModuleId = @DummyModuleId';
END

IF(@CanAdd IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
            BEGIN       
                SET @QueryString = @QueryString + ' WHERE a.CanAdd = @DummyCanAdd';
                SET @HasWhere=1;
            END
    ELSE SET @QueryString = @QueryString + ' AND a.CanAdd = @DummyCanAdd';
END

IF(@CanEdit IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
        BEGIN
            SET @QueryString = @QueryString + ' WHERE a.CanEdit = @DummyCanEdit';
            SET @HasWhere=1;
        END
    ELSE SET @QueryString = @QueryString + ' AND a.CanEdit = @DummyCanEdit';
END

IF(@CanDelete IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
        BEGIN
            SET @QueryString = @QueryString + ' WHERE a.CanDelete = @DummyCanDelete';
            SET @HasWhere=1;
        END
    ELSE SET @QueryString = @QueryString + ' AND a.CanDelete = @DummyCanDelete';
END

IF(@CreatedDatetime IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
    BEGIN
        SET @QueryString = @QueryString + ' WHERE a.CreatedDatetime = @DummyCreatedDatetime';
        SET @HasWhere=1;
    END
    ELSE SET @QueryString = @QueryString + ' AND a.CreatedDatetime = @DummyCreatedDatetime';
END

IF(@LastAccessDatetime IS NOT NULL)
BEGIN
    IF(@HasWhere=0) 
        BEGIN
            SET @QueryString = @QueryString + ' WHERE a.LastAccessDatetime = @DummyLastAccessDatetime';
            SET @HasWhere=1;
        END
    ELSE SET @QueryString = @QueryString + ' AND a.LastAccessDatetime = @DummyLastAccessDatetime';
END

IF(@Deleted IS NOT NULL)
BEGIN
  IF(@HasWhere=0)   
    BEGIN
        SET @QueryString = @QueryString + ' WHERE a.Deleted = @DummyDeleted';
        SET @HasWhere=1;
    END
  ELSE SET @QueryString = @QueryString + ' AND a.Deleted = @DummyDeleted';
END

PRINT @QueryString

EXECUTE SP_EXECUTESQL @QueryString
                      ,N'@DummyAccessRightId int, @DummyRoleId int, @DummyModuleId int, @DummyCanAdd char(1), @DummyCanEdit char(1), @DummyCanDelete char(1), @DummyCreatedDatetime datetime, @DummyLastAccessDatetime datetime, @DummyDeleted char(1)'
                      ,@DummyAccessRightId=@AccessRightId
                      ,@DummyRoleId=@RoleId
                      ,@DummyModuleId=@ModuleId
                      ,@DummyCanAdd=@CanAdd
                      ,@DummyCanEdit=@CanEdit
                      ,@DummyCanDelete=@CanDelete
                      ,@DummyCreatedDatetime=@CreatedDatetime
                      ,@DummyLastAccessDatetime=@LastAccessDatetime
                      ,@DummyDeleted=@Deleted;

ここで私は次のようにストアドプロシージャの入力パラメーターをnullに初期化しています

    @AccessRightId int=null,
@RoleId int=null,
@ModuleId int=null,
@CanAdd char(1)=null,
@CanEdit char(1)=null,
@CanDelete char(1)=null,
@CreatedDatetime datetime=null,
@LastAccessDatetime datetime=null,
@Deleted char(1)=null

それは私にとってはトリックでした。

これが同様の罠に陥った人に役立つことを願っています。


3

テンプレートが設定されていない場合(== nullなど)、このエラーも発生します。

その他のコメント:

パラメータを追加する時点でパラメータ値がわかっている場合は、AddWithValueを使用することもできます

EXECは必要ありません。SELECTで直接@templateパラメーターを参照できます。


0

まず、なぜEXECなのですか?それだけではいけません

AS
SELECT Column_Name, ...
FROM ...
WHERE TABLE_NAME = @template

現在のSPは意味がありませんか?特に、@ templateのvarchar値ではなく、@ templateに一致するを検索します。つまり、@ templateがの場合'Column_Name'、検索WHERE TABLE_NAME = Column_Nameは非常にまれです(テーブルと列に同じ名前を付けることはできません)。

あなたはまた、もし動的SQLを使用する必要があり、あなたが使用する必要がありますEXEC sp_ExecuteSQL(むしろ入力の連結より)インジェクション攻撃を防ぐために(パラメータとして値を維持します)。ただし、この場合は必要ありません。

実際の問題について-一見すると問題ありません。SPの別のコピーがぶら下がっていないことを確認しますか?これは一般的なエラーです...


その変更ではまだ機能しません。from句がparamから提供されたprocを以前使用していたため、このexecを誤って考えました。しかし、選択しただけでもエラーが発生します
Tony Peterson

とても好奇心が強い; たぶんタイプミスのトレブルチェック?
マークグラベル

0

ストアドプロシージャのパラメータにnull値が渡されたときに、今日このエラーに遭遇しました。デフォルト値= nullを追加してストアドプロシージャを変更することで、簡単に修正できました。


0

私は同じ問題を抱えていましたが、それを解決するには、ストアドプロシージャとまったく同じパラメーター名をパラメーターコレクションに追加するだけです。

ストアドプロシージャを作成するとします。

create procedure up_select_employe_by_ID 
     (@ID int) 
as
    select * 
    from employe_t 
    where employeID = @ID

したがって、ストアドプロシージャと同じようにパラメータに正確に名前を付けてください。

cmd.parameter.add("@ID", sqltype,size).value = @ID

もしあなたが行くなら

cmd.parameter.add("@employeID", sqltype,size).value = @employeid 

その後、エラーが発生します。


0

Stored Procが呼び出されていることを通知する必要があります。

comm.CommandType = CommandType.StoredProcedure;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.