过程期望没有提供的参数
在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
那么错误发生。