过程期望没有提供的参数

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

我试图找出我在这里做错了什么。

编辑:事实certificate,模板是空的,因为我从通过URL传递的参数获取它的值,我搞砸了传递的URL参数(我正在使用@而不是&

我会检查我的应用程序代码,看看你正在设置@template的值是什么。 我怀疑它是空的,其中存在的问题。

除了这里的其他答案,如果你忘记了把:

 cmd.CommandType = CommandType.StoredProcedure; 

那么你也会得到这个错误。

这个问题通常是由于上面提到的HLGEM将参数值设置为null而造成的 。 我想我会详细解释这个问题的一些解决scheme,我发现这个问题的新人有益于这个问题。

我更喜欢的解决scheme是默认存储过程参数为NULL(或任何你想要的值),这是上面提到的sangram ,但可能会因为答案非常冗长而被忽略。 有些东西是:

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

这意味着如果参数最终在某些情况下被设置为null,那么.NET将不会设置参数,存储过程将使用它定义的默认值。 另一个解决scheme,如果你真的想解决代码中的问题,将使用一个扩展方法来处理你的问题,如:

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

马特·汉密尔顿在这里有一个很好的post,列出了一些更好的扩展方法来处理这个领域。

我有一个问题,当我将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; 

其中dynamic构buildsearch查询我正在呼吁上面的一个:

 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; 

在这里,我正在初始化存储过程的input参数为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

如果Template没有设置(即== null),这个错误也会被提升。

更多评论:

如果在添加参数时知道参数值,也可以使用AddWithValue

EXEC不是必需的。 您可以直接在SELECT中引用@template参数。

首先 – 为什么是EXEC? 不应该这样

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

目前的SP没有意义? 特别是,它会寻找匹配@template的 ,而不是@template的varchar值。 即如果@template是'Column_Name' ,它将searchWHERE TABLE_NAME = Column_Name ,这是非常罕见的(使表和列名称相同)。

另外,如果您必须使用dynamicSQL,则应使用EXEC sp_ExecuteSQL (将值保留为参数)以防止注入攻击(而不是input串联)。 但在这种情况下并不是必须的。

重新解决实际问题 – 一目了然, 你确定你没有不同的SP副本吗? 这是一个常见的错误…

我今天遇到这个错误,当空值传递给我的存储过程的参数。 我可以通过添加默认值= null来修改存储过程。

我有同样的问题,要解决它只是添加完全相同的参数名称,您的参数集合中的存储过程。

假设您创build一个存储过程:

 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 

那么错误发生。