如何在VB.NET中合并两个特定结构的DataView?
解决方案:合并两个DataView为单行数据
看起来你想要把两个分别包含Credit(Debit为0)和Debit(Credit为0)的DataView合并成一行,同时包含CodeClt、Client、Credit、Debit四个字段。原代码里的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




