You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在VB.NET中合并两个特定结构的DataView?

解决方案:合并两个DataView为单行数据

看起来你想要把两个分别包含CreditDebit为0)和DebitCredit为0)的DataView合并成一行,同时包含CodeCltClientCreditDebit四个字段。原代码里的Table.Merge方法会将两个表的行直接合并,最终会得到两行数据(如果两个查询都有结果),这不符合你的预期。下面提供两种可行的方案:

方案1:用SQL直接聚合(推荐)

把合并逻辑放到数据库层,通过UNION ALL将两个查询的结果合并,再用SUM聚合得到单行数据。这种方式效率更高,代码也更简洁:

Sub Facture_old_Getdata()
    Dim sRs As String
    Dim mergedDataView As DataView
    
    ' 构造聚合查询:先合并两个表的结果,再汇总Credit和Debit
    sRs = " SELECT CodeClt, Client, SUM(Credit) As Credit, SUM(Debit) As Debit " _
          & " FROM ( " _
          & "     -- 从LV_Fact_CLient获取Credit数据,Debit设为0 " _
          & "     SELECT CodeClt, Client, Sum(MontantTTc) As Credit, 0 As Debit " _
          & "     FROM LV_Fact_CLient " _
          & "     WHERE Codeclt ='" & TxtCodeClient.Text & "'" _
          & "     GROUP BY Codeclt, Client " _
          & "     UNION ALL " _
          & "     -- 从Gestionreg获取Debit数据,Credit设为0 " _
          & "     SELECT Codeclt, Client, 0 As Credit, SUM(Montant) As Debit " _
          & "     FROM Gestionreg " _
          & "     WHERE Codeclt ='" & TxtCodeClient.Text & "'" _
          & "     GROUP BY Codeclt, Client " _
          & " ) AS Combined " _
          & " GROUP BY CodeClt, Client "
    
    ' 获取合并后的DataView,直接就是一行数据
    mergedDataView = c_DataSql.fGet_Data_ViewAccess(sRs)
    
    ' 这里可以将mergedDataView赋值给你需要的变量使用
End Sub

方案优势:

  • 数据库层面处理聚合,比客户端代码合并效率更高,尤其是数据量较大时
  • 自动处理其中一个表无数据的情况(SUM会自动忽略空值,返回0)
  • 代码逻辑更清晰,减少客户端的处理步骤

方案2:在VBA代码中手动合并

如果无法修改SQL查询,可以在代码中提取两个DataView的数值,手动创建一个包含合并后数据的DataView:

Sub Facture_old_Getdata()
    Dim sRs, sRs1 As String
    Dim dvCredit As DataView, dvDebit As DataView
    Dim resultTable As DataTable
    Dim creditValue As Double, debitValue As Double
    Dim codeClt As String, clientName As String
    
    ' 获取Credit数据视图
    sRs = " select CodeClt, client, Sum(MontantTTc) As Credit, 0 As Debit " _
          & "from LV_Fact_CLient " _
          & "where Codeclt ='" & TxtCodeClient.Text & "'" _
          & "group by Codeclt, Client"
    dvCredit = c_DataSql.fGet_Data_ViewAccess(sRs)
    
    ' 获取Debit数据视图
    sRs1 = "select Codeclt, Client, 0 As Credit, SUM(Montant) As Debit " _
           & " from Gestionreg " _
           & "where Codeclt ='" & TxtCodeClient.Text & "'" _
           & "group by Codeclt, Client"
    dvDebit = c_DataSql.fGet_Data_ViewAccess(sRs1)
    
    ' 初始化默认值
    creditValue = 0
    debitValue = 0
    codeClt = TxtCodeClient.Text
    clientName = ""
    
    ' 提取Credit值和客户名称(如果有数据)
    If dvCredit.Count > 0 Then
        creditValue = CDbl(dvCredit(0)("Credit"))
        clientName = dvCredit(0)("client").ToString()
    End If
    
    ' 提取Debit值,若之前未获取到客户名称则从这里补充
    If dvDebit.Count > 0 Then
        debitValue = CDbl(dvDebit(0)("Debit"))
        If clientName = "" Then
            clientName = dvDebit(0)("Client").ToString()
        End If
    End If
    
    ' 创建结果DataTable并定义字段
    resultTable = New DataTable()
    resultTable.Columns.Add("CodeClt", GetType(String))
    resultTable.Columns.Add("Client", GetType(String))
    resultTable.Columns.Add("Credit", GetType(Double))
    resultTable.Columns.Add("Debit", GetType(Double))
    
    ' 添加合并后的单行数据
    Dim newRow As DataRow = resultTable.NewRow()
    newRow("CodeClt") = codeClt
    newRow("Client") = clientName
    newRow("Credit") = creditValue
    newRow("Debit") = debitValue
    resultTable.Rows.Add(newRow)
    
    ' 转为DataView使用
    Dim mergedDataView As DataView = New DataView(resultTable)
End Sub

方案优势:

  • 不需要修改SQL查询逻辑,适合无法调整数据库查询的场景
  • 灵活处理各种边界情况(比如其中一个查询无结果)

注意事项:SQL注入风险

当前代码中直接拼接TxtCodeClient.Text到SQL语句中,存在SQL注入的风险(比如用户输入包含单引号会导致SQL语法错误)。建议使用参数化查询来避免这个问题,以Access为例,可以修改为:

Sub Facture_old_Getdata()
    Dim cmd As New OleDbCommand
    Dim conn As OleDbConnection
    Dim dt As New DataTable
    Dim mergedDataView As DataView
    
    ' 获取数据库连接(替换为你实际的连接获取逻辑)
    conn = c_DataSql.GetConnection()
    
    ' 参数化SQL查询
    Dim sRs As String = " SELECT CodeClt, Client, SUM(Credit) As Credit, SUM(Debit) As Debit " _
          & " FROM ( " _
          & "     SELECT CodeClt, Client, Sum(MontantTTc) As Credit, 0 As Debit " _
          & "     FROM LV_Fact_CLient " _
          & "     WHERE Codeclt = ? " _
          & "     GROUP BY Codeclt, Client " _
          & "     UNION ALL " _
          & "     SELECT Codeclt, Client, 0 As Credit, SUM(Montant) As Debit " _
          & "     FROM Gestionreg " _
          & "     WHERE Codeclt = ? " _
          & "     GROUP BY Codeclt, Client " _
          & " ) AS Combined " _
          & " GROUP BY CodeClt, Client "
    
    cmd.CommandText = sRs
    cmd.Connection = conn
    ' 添加参数,避免SQL注入
    cmd.Parameters.AddWithValue("@CodeClt", TxtCodeClient.Text)
    cmd.Parameters.AddWithValue("@CodeClt", TxtCodeClient.Text)
    
    ' 填充DataTable
    Dim adapter As New OleDbDataAdapter(cmd)
    adapter.Fill(dt)
    
    mergedDataView = New DataView(dt)
End Sub

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

火山引擎 最新活动