【问题标题】:Procedure or function in stored procedure has too many arguments specified存储过程中的过程或函数指定的参数过多
【发布时间】:2019-03-11 19:03:00
【问题描述】:

我遇到了以下代码的问题,无法弄清楚它有什么问题:

存储过程:

CREATE PROCEDURE [dbo].[spAddRateTypeRoomTypeCombination]
(
     @RatePlanName NVARCHAR(50),
     @OpenFrom DATE,
     @OpenTo DATE,
     @Active BIT,
     @RoomTypeId INT)
AS
    DECLARE @Result INT

   BEGIN TRANSACTION

   IF EXISTS (SELECT NULL FROM dbo.RateType WITH (UPDLOCK)
              WHERE RatePlanName = @RatePlanName) 
   BEGIN
       SELECT @Result = -1
   END
   ELSE
   BEGIN
       INSERT INTO dbo.RateType (RatePlanName, OpenFrom, OpenTo, Active)
       VALUES (@RatePlanName, @OpenFrom, @OpenTo, @Active)

        /******  return the last identity value inserted into an identity column ******/
       DECLARE @RateTypeid INT
       SET @RateTypeId = SCOPE_IDENTITY()

       INSERT INTO dbo.RateRoomCombination(RateTypeId, RoomTypeId)
       VALUES (@RateTypeId, @RoomTypeId)

       SELECT @Result = @@ERROR
   END

   IF @Result <> 0
   BEGIN
       ROLLBACK
   END
   ELSE
   BEGIN
       COMMIT
   END
   RETURN @Result
GO

这是我为了将数据插入到我的 2 个表 RateTypeRateRoomCombination 中而编写的函数:

Function AddRateType(RatePlanName As String) As Integer
    Using con As SqlConnection = New SqlConnection(GetConnectionString())
        Dim cmd As New SqlCommand()
        cmd.CommandType = CommandType.StoredProcedure
        cmd.CommandText = "spAddRateTypeRoomTypeCombination"
        cmd.Parameters.Add("@RatePlanName", SqlDbType.NVarChar).Value = TextBoxRateName.Text.Trim()
        cmd.Parameters.Add("@Active", SqlDbType.Bit).Value = CheckBox3.Checked
        cmd.Parameters.AddWithValue("@OpenFrom", Convert.ToDateTime(Textbox1.Text.Trim()))
        cmd.Parameters.AddWithValue("@OpenTo", Convert.ToDateTime(Textbox2.Text.Trim()))
        cmd.Parameters.Add(New SqlParameter("@Result", SqlDbType.Int))
        cmd.Parameters("@Result").Direction = ParameterDirection.ReturnValue
        For Each item As ListItem In chkRoomTypes.Items
            cmd.Parameters.Add(New SqlParameter("@RateTypeId", SqlDbType.Int))
            cmd.Parameters.Add(New SqlParameter("@RoomTypeId", SqlDbType.Int))
        Next
        Dim commandResult As Integer = 1
        cmd.Connection = con
        Try
            con.Open()
            cmd.ExecuteNonQuery()
            commandResult = CType(cmd.Parameters("@Result").Value, Integer)
        Catch ex As System.Data.SqlClient.SqlException
            commandResult = ex.Number
            ' Use the following 3 lines to understand better the error
            Dim msg As String = "Insert Error:"
            msg += ex.Message
            Throw New Exception(msg)
        Finally
            con.Close()
            con.Dispose()
        End Try
        Return commandResult
    End Using
End Function

我得到的错误:

System.Exception: '插入错误:过程或函数 spAddRateTypeRoomTypeCombination 指定了太多参数。'

如果我使用 1 个 RateTypeId 和 1 个 RoomTypeId 从 SQL 执行我的存储过程,我的数据库就会更新。如果我添加超过 1 个 RoomTypeId(我试图在我的页面上执行的情况),SQL 会抛出与上述相同的错误:参数过多。

我真的不知道哪里出了问题。

谢谢

【问题讨论】:

  • 直接执行时运行的是什么命令?向存储过程传递太多参数应该总是抛出同样的错误消息。
  • 我执行 DB] GO EXEC dbo.spAddRateTypeAndRoomtareCombination_UsingExists @RatePlanName = 'Standard', @OpenFrom='2019-03-10T00:00:00', @OpenTo='2019-04-10T00:00 :00',@Active=True,@RoomTypeId='5'
  • 您的帖子说您从 SQL 执行时使用“1 RateTypeId 和 1 RoomTypeId”。该命令中没有指定 RateTypeID。在您的函数中,您尝试使用的参数多于存储过程中指定的参数。您在存储过程定义中指定了 5 个参数,仅此而已。你不能随意在调用中添加参数——它不是那样工作的。你需要做一些事情,比如建立一个列表,然后在存储过程中拆分它,或者创建一个用户定义的表类型,然后传递你的值。

标签: sql-server stored-procedures ado.net


【解决方案1】:

您的错误有两个原因,它们都在这里:

    For Each item As ListItem In chkRoomTypes.Items
        cmd.Parameters.Add(New SqlParameter("@RateTypeId", SqlDbType.Int))
        cmd.Parameters.Add(New SqlParameter("@RoomTypeId", SqlDbType.Int))
    Next
  1. 您的存储过程甚至没有@RateTypeId 参数(它有一个同名的局部变量)。所以你不能在你的 .net 命令中向它传递参数。

  2. 存储过程中的 @RoomTypeId 参数是 INT 类型。这意味着您只能将一个 int 值传递给它。您不能将多个@RoomTypeId 参数添加到.net 命令并将其传递给此存储过程。如果您想这样做,您应该考虑将其设为表值参数。

【讨论】:

  • 你的意思是每次我需要在多对多/联合表中插入更多的 1 行,就像我尝试做的那样,我总是需要创建一个表值参数?
  • 是的,一个SQL命令不能添加多个同名参数,所以如果你有多个RateTypeId要传递,那么你需要将它们都传递到一个单参数。您可以使用分隔字符串而不是 TVP,但 TVP 在存储过程代码中更容易处理。
  • 非常感谢。最后一个问题:我仍然可以使用 DECLARE RateTypeid INT SET RateTypeId = SCOPE_IDENTITY() 来添加 RateTypeId 吗?简而言之,我需要 TVP 获取几种房间类型的 Id,并获取与房间关联的最后一个 RateTypeId。
  • 是的,您可以这样做,在这种情况下,您根本不会从 .net 应用程序传递 @RateTypeID 参数。严格来说,它是存储过程中的局部变量。
  • 嗨@Tab Alleman,我肯定会按照你的建议进行TVP。我现在正在创建要分配给我的应用程序代码的参数名称的 DataTable。 Private Function GetRoomTypeIds() As DataTable Dim dt As New DataTable() dt.Columns.AddRange(New DataColumn(1) {New DataColumn("Id", GetType(Integer)), New DataColumn("RoomTypeId", GetType(Integer) )}) 对于每个 li As ListItem In chkRoomTypes.Items dt.Rows.Add(txtId1.Text, chkRoomTypes.SelectedValue) Next Return dt End Function
猜你喜欢
  • 2023-03-26
  • 2014-02-08
  • 2015-12-10
  • 2016-02-22
相关资源
最近更新 更多