프로 시저에 제공되지 않은 매개 변수가 필요합니다.


106

SQL Server에서 저장 프로 시저에 액세스 할 때 오류가 발생합니다.

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

이것은 매개 변수를 (System.data.SqlClient)제공하더라도 .net의 sql 데이터 연결을 통해 매개 변수가있는 저장 프로 시저를 호출 할 때 발생 합니다. 다음은 내 코드입니다.

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 매개 변수를 망 쳤기 때문에 템플릿이 null이었습니다 ( @대신 for 및 대신 사용 &)


아주 오래된 질문이지만 동일한 문제가 발생했으며 제 경우에는 @parameter 중 하나에 추가 공백을 추가 한 것을 보지 못했습니다. 1 시간의 디버깅.
— Léon Pelletier 2012-06-16

저장 프로 시저를 실행하고이 오류를 가져 오는 방법 은 stackoverflow.com/a/26374810/1860652 를 참조하십시오
— AlexFoxGill

이것은 어떤 이유로 든 오늘 첫 페이지에 게시되었습니다. 그러나 "템플릿"값이 클라이언트 URL에서 오는 경우 SQL 주입에 취약한 것처럼 들립니다! 적어도 나는 사용을 제안합니다QUOTENAME(@template)
— Mark Sowul

답변:


85

내 응용 프로그램 코드를 확인하고 @template을 설정하는 값을 확인합니다. 나는 그것이 무효라고 생각하고 거기에 문제가 있습니다.


예, 템플릿이 null입니다. 이전에 설정하는 것을 잊었습니다.
— Tony Peterson

35
난 그냥 DBNULL가 C 번호의 가장 쓸모없는 "기능"이라고 추가 할 수
— thaBadDawg

295

여기에 다른 답변 외에도 다음을 입력하는 것을 잊은 경우 :

cmd.CommandType = CommandType.StoredProcedure;

그러면이 오류도 발생합니다.


Visual Studio에서 디버깅하는 경우 선택한 데이터 세트의 이름 옆에있는 보고서의 데이터 탭 [레이아웃 및 미리보기 탭 옆]에 CommandType을 변경할 수있는 또 다른 드롭 다운 컨트롤이 있습니다. 즐겨!
— SarjanWebDev

2
예, SqlException은 이상합니다. 프로 시저로 알고 있다는 것을 알려주지 만 프로 시저임을 알리려면 CommandType 속성을 설정해야합니다!
— Tahir Hassan

@Tahir, 나는 오류가 의도가 SQL DB 저장 프로 시저라는 것을 알고 있음을 암시하는 것보다 "프로 시저"를 일반 용어 ( "또는 함수"추가로 제 안됨)로 사용하는 것보다 더 많다고 생각합니다.
— Brian

3
이것이 제가 상상하는 99 %의 사람들을위한 해결책입니다
— Jonesopolis

젠장, 솔루션이 왜 이렇게 쉬웠습니까? 감사합니다. 매개 변수가 존재하고 null이 아니라는 것을 알았으며 이것이 필요한 전부였습니다.
— BornToDoStuff 2019

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);
}

매트 해밀턴은 좋은 게시물을 가지고 여기에 목록이 좀 더 큰 확장 방법이 지역을 처리 할 때있다.


12

정수 매개 변수에 0을 제공하면 오류가 발생하는 문제가 발생했습니다. 그리고 다음을 발견했습니다.

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

작동하지만 그렇지 않습니다.

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

6
두 번째가 작동하지 않는 이유는 컴파일러가 SqlParameter 생성자 의 (string, SqlDbType) 오버로드를 호출하고 있다고 생각하기 때문 입니다. 비고 참조여기에서 하십시오 .
— Keith

1
사용하려는 경우 Add구문 거나 명령에 개체 이니셜 라이저를 사용하는 경우 명명 된 매개 변수를 사용할 수 있습니다.cmd.Parameters.Add(new SqlParameter("@Status", value: 0));
— user888734

7

제 경우 DBNULL.Value에는 정의되지 않은 저장 프로 시저 매개 변수에 대한 코드에서 (else 조건 사용) 전달해야 null했지만 값은 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

매우 호기심이 많다. 오타에 대한 고음 검사?
— Marc Gravell

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.