Процедура ожидает параметр, который не был указан
Я получаю сообщение об ошибке при доступе к хранимой процедуре в 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);
Я пытаюсь понять, что я делаю неправильно здесь.
Edit: как оказалось, шаблон был null потому что я получал его значение из параметра, переданного через URL, и я испортил передачу url param (я использовал @
и вместо &
)
10 ответов:
Я бы проверил свой код приложения и посмотрел, какое значение вы устанавливаете @template. Я подозреваю, что это null и в этом заключается проблема.
В дополнение к другим ответы здесь, Если вы забыли поставить:
вы также получите эту ошибку.cmd.CommandType = CommandType.StoredProcedure;
этот вопрос, действительно, как правило, вызвана установка параметра в значение null в качестве HLGEM упоминалось выше. Я думал, что буду подробно останавливаться на некоторых решениях этой проблемы, которые я нашел полезными для людей, незнакомых с этой проблемой.
решение, которое я предпочитаю, - это значение по умолчанию для параметров хранимой процедуры NULL (или любое другое значение, которое вы хотите), которое было упомянуто Санграм выше, но может быть пропущено, потому что ответ очень многословен. Что-то вроде:
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); }
Мэтт Гамильтон имеет хороший пост здесь что списки еще несколько отличных методов расширения при работе с этой областью.
у меня была проблема, когда я получал ошибку, когда я предоставлял 0 целочисленному параметру. И обнаружил, что:
cmd.Parameters.AddWithValue("@Status", 0);
работает, но это не:
cmd.Parameters.Add(new SqlParameter("@Status", 0));
я сталкиваюсь с подобной проблемой при вызове хранимой процедуры
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
что сделал трюк для меня.
Я надеюсь, что это будет полезно для тех, кто падает в подобной ловушке.
для моего случая, я должен был пройти
DBNULL.Value
(используя условие if else) из кода для параметра хранимых процедур, которые не определеныnull
но значениеnull
.
Если шаблон не установлен (т. е. ==null), эта ошибка также будет вызвана.
комментарии:
Если вы знаете значение параметра к моменту добавления параметров, вы также можете использовать AddWithValue
EXEC не требуется. Вы можете напрямую ссылаться на параметр @template в SELECT.
во - первых-почему это EXEC? Разве это не должно быть просто
AS SELECT Column_Name, ... FROM ... WHERE TABLE_NAME = @template
текущий SP не имеет смысла? В частности, что бы искать колонки соответствие @template, а не значение varchar @template. т. е. если @template
'Column_Name'
он будет искатьWHERE TABLE_NAME = Column_Name
, что очень редко (чтобы таблица и столбец назывались одинаково).также, если вы do должны использовать динамический SQL, вы должны использовать
EXEC sp_ExecuteSQL
(удержание значения в качестве параметров) в предотвратите от атак впрыски (а не конкатенации входного сигнала). Но это не обязательно в данном случае.Re фактическая проблема-это выглядит нормально с первого взгляда; вы уверены, что у вас нет другой копии SP висит вокруг? Это распространенная ошибка...
Я столкнулся с этой ошибкой сегодня, когда нулевые значения были переданы в параметры моей хранимой процедуры. Я смог легко исправить, изменив хранимую процедуру, добавив значение по умолчанию = null.
у меня была такая же проблема, решить ее просто добавить точно такое же имя параметра в коллекции параметров в хранимых процедурах.
пример
допустим, вы создаете хранимую процедуру:
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
затем происходит ошибка.