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

VB.NET下如何按contentID关联对比两份Excel并生成合并结果Excel

按contentID关联匹配+数据对比的实现思路(适配你现有EPPlus代码)

核心逻辑前置

你现在的独立列存储方式没法高效按contentID匹配,要先把两份Excel的行数据改成以处理后的contentID为键的Dictionary存储,匹配时间从O(n*m)降到O(n+m),还能避免列错位问题。

第一步:改造现有读取逻辑,用Dictionary存行数据

统一contentID格式化规则(必做,否则大概率匹配失败)

先把所有读出来的contentID做统一处理,再当字典键:

  • 去首尾空格:Dim cid = rawCellValue.ToString().Trim()
  • 数字型contentID转无格式字符串:如果是数字,转成整数/字符串,去掉.0后缀,比如把123.0转成"123"
  • 带字母的统一大小写:比如全转小写cid = cid.ToLower()

定义字典存储两份表的行数据

' 1. 存储第一份「交付表」(含delivery number、contentID、packages、volume)
' 值的结构:(DeliveryNo As String, Packages As String, Volume As String)
Dim deliveryDict As New Dictionary(Of String, (DeliveryNo As String, Packages As String, Volume As String))

' 2. 存储第二份「SPS表」(含SPS Number、folder number、contentID、packages、volume)
Dim spsDict As New Dictionary(Of String, (SPSNo As String, FolderNo As String, Packages As String, Volume As String))

读Excel行时写入字典

读每一行时,先拿处理后的contentID,再把该行其他字段存进字典,重复contentID的处理逻辑按需加:

' 示例:读交付表的每一行
For Each row In deliveryWorksheet.Rows
    ' 跳过空行
    If row.Cells("contentID").Text.Trim() = "" Then Continue For

    ' 处理contentID当字典键
    Dim cidKey = row.Cells("contentID").Text.Trim()
    ' 如果是数字型contentID,额外处理:比如把123.0转成123
    Dim cidNum As Decimal
    If Decimal.TryParse(cidKey, cidNum) Then cidKey = cidNum.ToString("0")

    ' 重复contentID判断(按需选择覆盖/跳过/报错)
    If deliveryDict.ContainsKey(cidKey) Then
        ' 这里选择覆盖:或者写日志记录重复值
        Console.WriteLine($"交付表重复contentID:{cidKey},已用最新行覆盖")
    End If

    ' 写入字典
    deliveryDict(cidKey) = (
        DeliveryNo:= row.Cells("delivery number").Text.Trim(),
        Packages:= row.Cells("packages").Text.Trim(),
        Volume:= row.Cells("volume").Text.Trim()
    )
Next

SPS表的读取逻辑完全同理,对应存SPS Number、folder number到spsDict即可。

第二步:关联匹配+对比逻辑

先合并所有contentID去重

遍历两个字典的所有键,覆盖只在SPS表、只在交付表、两边都有的三种场景:

' 合并两个表的所有contentID,去重后遍历
Dim allCids = spsDict.Keys.Union(deliveryDict.Keys)

逐行生成结果Excel的数据

你已经初始化了结果表的表头,接下来从第2行开始写数据:

' 结果表当前行号,从2开始(第1行是表头)
Dim resultRowNum As Integer = 2

For Each cid In allCids
    ' 先初始化所有列的默认值
    Dim spsNo As String = ""
    Dim folderNo As String = ""
    Dim deliveryNo As String = ""
    Dim packages As String = ""
    Dim volume As String = ""
    Dim pkgDiff As Boolean = False
    Dim volDiff As Boolean = False

    ' 1. 从SPS表取数据
    Dim hasSps As Boolean = spsDict.ContainsKey(cid)
    If hasSps Then
        spsNo = spsDict(cid).SPSNo
        folderNo = spsDict(cid).FolderNo
    End If

    ' 2. 从交付表取数据,同时对比packages/volume
    Dim hasDelivery As Boolean = deliveryDict.ContainsKey(cid)
    If hasDelivery Then
        deliveryNo = deliveryDict(cid).DeliveryNo

        ' 两边都有数据时做对比
        If hasSps Then
            ' 注意:数值类的packages/volume一定要转Decimal再比,不要比字符串
            Dim spsPkg As Decimal, delPkg As Decimal
            Decimal.TryParse(spsDict(cid).Packages, spsPkg)
            Decimal.TryParse(deliveryDict(cid).Packages, delPkg)
            pkgDiff = spsPkg <> delPkg

            Dim spsVol As Decimal, delVol As Decimal
            Decimal.TryParse(spsDict(cid).Volume, spsVol)
            Decimal.TryParse(deliveryDict(cid).Volume, delVol)
            volDiff = spsVol <> delVol

            ' 按需设置packages/volume的展示内容:比如差异时标注两边的值,一致就直接写
            packages = If(pkgDiff, $"差异(SPS:{spsDict(cid).Packages} / 交付:{deliveryDict(cid).Packages})", spsDict(cid).Packages)
            volume = If(volDiff, $"差异(SPS:{spsDict(cid).Volume} / 交付:{deliveryDict(cid).Volume})", spsDict(cid).Volume)
        Else
            ' 只有交付表有数据,直接写交付表的值
            packages = deliveryDict(cid).Packages
            volume = deliveryDict(cid).Volume
        End If
    Else
        ' 只有SPS表有数据,直接写SPS表的值
        If hasSps Then
            packages = spsDict(cid).Packages
            volume = spsDict(cid).Volume
        End If
    End If

    ' 写入结果表对应单元格(对应需求的表头顺序:SPS number、folder number、delivery number、contentID、packages、volume)
    resultWorksheet.Cells(resultRowNum, 1).Value = spsNo
    resultWorksheet.Cells(resultRowNum, 2).Value = folderNo
    resultWorksheet.Cells(resultRowNum, 3).Value = deliveryNo
    resultWorksheet.Cells(resultRowNum, 4).Value = cid
    resultWorksheet.Cells(resultRowNum, 5).Value = packages
    resultWorksheet.Cells(resultRowNum, 6).Value = volume

    ' 可选:给差异单元格加背景色标记
    If pkgDiff Then
        resultWorksheet.Cells(resultRowNum, 5).Style.Fill.PatternType = OfficeExcelFillStyle.Solid
        resultWorksheet.Cells(resultRowNum, 5).Style.Fill.BackgroundColor.SetColor(Color.LightPink)
    End If
    If volDiff Then
        resultWorksheet.Cells(resultRowNum, 6).Style.Fill.PatternType = OfficeExcelFillStyle.Solid
        resultWorksheet.Cells(resultRowNum, 6).Style.Fill.BackgroundColor.SetColor(Color.LightPink)
    End If

    ' 行号递增
    resultRowNum += 1
Next

初学者必踩坑提醒

  • 不要直接对比字符串型的数值:Excel读出来的packages/volume如果是数字,直接比字符串会出现"1.0"和"1"不匹配的假差异,必须转Decimal再比较
  • contentID格式化必须统一:比如带空格、大小写、数字带小数点的情况不处理,会出现大量匹配不上的问题
  • 空contentID直接跳过:不要把空值当字典键,避免匹配混乱
  • 重复contentID提前处理:不要默认同一个Excel里contentID唯一,加判断逻辑避免数据被意外覆盖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 12:06:08