You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

StoreBillingDetailsToMonthlyTable()执行位置及代码问题排查求助

问题定位与解决:StoreBillingDetailsToMonthlyTable()不生效的原因及修复

一、代码本身的核心错误(函数不生效的主要原因)

你的函数无法向monthly_table插入数据,核心问题出在函数内部的SQL和参数处理上,和放置位置关系不大:

1. INSERT语句参数不匹配

你写的插入SQL:

INSERT INTO isp_database.monthly_table (month_name, bill_no, client_id, amount_paid, date_paid) VALUES (@bill_no, @client_id, @amount_paid, @date_paid)

列有5个,但VALUES里只写了4个参数,缺少了@month_name,且参数顺序完全不匹配字段顺序,数据库无法解析。

2. 参数类型错误:用了SqlDbType而非MySqlDbType

你使用的是MySQL数据库,但参数类型用的是SqlDbType(SQL Server专属类型),应替换为MySqlDbType,否则参数无法正确映射。

3. 未处理重复插入逻辑

每次调用函数都会遍历所有符合条件的记录插入,会导致重复数据,若monthly_table有唯一约束,还会直接触发插入失败。

4. 日期判断逻辑缺陷

如果用户在当月最后几天支付,但系统日期已到下个月,currentMonth会是下个月,导致当月支付的记录无法插入月度表。应该用支付日期的月份匹配,而非当前系统日期。

5. 其他潜在错误

  • UpdateStatusToUnpaid里的SQL错误:where date=NULL 需改为 where date IS NULL,SQL中判断NULL必须用IS NULL而非=。
  • 数据库连接和命令未用Using语句包裹,可能导致连接泄漏,影响后续操作。

二、修复后的StoreBillingDetailsToMonthlyTable函数

Public Sub StoreBillingDetailsToMonthlyTable(Optional ByVal targetBillId As Integer = 0)
    ' Using语句确保连接自动释放
    Using Conn1 As New MySqlConnection("server=localhost; userid=root; password=root; database=isp_database;")
        Conn1.Open()

        ' 可选:只处理指定账单(比如刚支付的账单),避免全表遍历
        Dim selectQuery As String = If(targetBillId > 0, 
            "SELECT * FROM isp_database.bill_table WHERE bill_id = @bill_id", 
            "SELECT * FROM isp_database.bill_table WHERE date IS NOT NULL")
        Using selectCommand As New MySqlCommand(selectQuery, Conn1)
            If targetBillId > 0 Then
                selectCommand.Parameters.AddWithValue("@bill_id", targetBillId)
            End If

            Using reader As MySqlDataReader = selectCommand.ExecuteReader()
                While reader.Read()
                    Dim client_id As Integer = CInt(reader("client_id"))
                    Dim bill_no As Integer = CInt(reader("bill_id"))
                    Dim amount_paid As Decimal = If(reader.IsDBNull(reader.GetOrdinal("amount")), 0, CDec(reader("amount")))
                    Dim date_paid As DateTime = CDate(reader("date"))

                    ' 用支付日期的月份作为月度表的月份,而非当前系统日期
                    Dim monthName As String = date_paid.ToString("MMMM")

                    ' 先检查是否已存在该记录,避免重复插入
                    Using checkCmd As New MySqlCommand("SELECT COUNT(*) FROM isp_database.monthly_table WHERE bill_no = @bill_no", Conn1)
                        checkCmd.Parameters.AddWithValue("@bill_no", bill_no)
                        Dim count As Integer = CInt(checkCmd.ExecuteScalar())
                        If count > 0 Then Continue While ' 已存在则跳过
                    End Using

                    ' 修正后的INSERT语句,参数顺序匹配列顺序
                    Dim insertQuery As String = "INSERT INTO isp_database.monthly_table (month_name, bill_no, client_id, amount_paid, date_paid) VALUES (@month_name, @bill_no, @client_id, @amount_paid, @date_paid)"
                    Using insertCommand As New MySqlCommand(insertQuery, Conn1)
                        ' 使用MySqlDbType匹配MySQL类型
                        insertCommand.Parameters.Add("@month_name", MySqlDbType.VarChar).Value = monthName
                        insertCommand.Parameters.Add("@bill_no", MySqlDbType.Int32).Value = bill_no
                        insertCommand.Parameters.Add("@client_id", MySqlDbType.Int32).Value = client_id
                        insertCommand.Parameters.Add("@amount_paid", MySqlDbType.Decimal).Value = amount_paid
                        insertCommand.Parameters.Add("@date_paid", MySqlDbType.Date).Value = date_paid

                        insertCommand.ExecuteNonQuery()
                    End Using
                End While
            End Using
        End Using
    End Using
End Sub

三、正确的函数放置位置

函数的最佳调用时机是用户完成支付后,即在Button1_Click的支付逻辑执行完成后调用,同时传入当前支付的账单ID,避免全表遍历:

修改Button1_Click:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles paid_btn.Click
    MysqlConn = New MySqlConnection()
    MysqlConn.ConnectionString = "server=localhost; userid=root; password=root; database=isp_database"

    Try
        MysqlConn.Open()

        Dim inDate As DateTime = DateTimePicker1.Value
        Dim Query As String = "update isp_database.bill_table set status= 'PAID', connection='CONNECTED', penalty=NULL, date= @date where client_id= @client_id"
        ' 改用参数化查询,避免SQL注入和格式错误
        Command = New MySqlCommand(Query, MysqlConn)
        Command.Parameters.AddWithValue("@date", inDate)
        Command.Parameters.AddWithValue("@client_id", cid_tb.Text)
        Command.ExecuteNonQuery()
        
        Dim cid As String = cid_tb.Text.ToString()
        MessageBox.Show("CUSTOMER " & cid & " PAID!")

        MysqlConn.Close()
        Display_Table()

        ' 从DataGridView获取当前支付的账单ID(假设选中了对应行)
        If DataGridView1.SelectedRows.Count > 0 Then
            Dim billId As Integer = CInt(DataGridView1.SelectedRows(0).Cells("bill_id").Value)
            StoreBillingDetailsToMonthlyTable(billId)
        End If

    Catch ex As MySqlException
        MessageBox.Show(ex.Message)
        cid_tb.Text = ""
        name_tb.Text = ""
        plan_tb.Text = ""
        price_tb.Text = ""

    End Try
End Sub

若需要每月自动同步所有当月支付记录,可保留Timer中的调用,但建议限定在月末执行,同时确保重复插入逻辑已处理。

四、额外建议

  • 所有SQL操作都使用参数化查询,避免SQL注入和格式错误(比如UpdateDateDue函数直接拼接日期字符串,容易出错)。
  • 数据库连接、命令、DataReader都用Using语句包裹,确保资源自动释放,避免连接泄漏。

内容的提问来源于stack exchange,提问作者niks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:37:20