Excel Scripting Dictionary VBA – 区分重复项

Excel Scripting Dictionary VBA – 区分重复项

问题描述

我有两个表格,我想根据集装箱号码将它们连接起来。我的问题是,集装箱在3个月后可能会重复,这会将所有数量汇总在一起。表1中,我有集装箱号码以及它们的处理日期。表2中有集装箱号码、数量和发票日期。我认为,通过查看处理日期和发票日期之间的差值,并限制最大30天,可以将集装箱号码和正确数量的匹配,因为一个集装箱不能在至少3个月内重复。

请参考下面的代码,我使用脚本字典将表2中的集装箱、数量和发票日期写入。然后,表1循环处理日期。我的初步问题是,当循环进行时,它只捕获一行,而不是我需要的多行数量的总和。有什么建议吗?如果有更好的方法,我愿意学习。谢谢!

Sub joinTables()

Dim wLo As ListObject
Dim cLo As ListObject
Set wLo = wmsWks.ListObjects("Tbl2")
Set cLo = clincWks.ListObjects("Tbl1")

Dim containerDict As Object
Set containerDict = CreateObject("Scripting.Dictionary")

  'fill the dictionary with WMS data, summing qty
  Dim i As Long
  For i = 1 To wLo.ListRows.Count
    Container = wLo.ListColumns("Container").DataBodyRange(i).Value
    allocQty = wLo.ListColumns("AllocatedQty").DataBodyRange(i).Value
    invQty = wLo.ListColumns("InvoiceQty").DataBodyRange(i).Value
    invDate = wLo.ListColumns("InvoiceDate").DataBodyRange(i).Value

      If containerDict.exists(Container) Then
        containerDict(Container)(0) = containerDict(Container)(0) + allocQty
        containerDict(Container)(1) = containerDict(Container)(1) + invQty
      Else
        containerDict(Container) = Array(allocQty, invQty, invDate)
      End If

  Next i

  'headers
  joinWks.Cells(1, 1).Value = "Container"
  joinWks.Cells(1, 2).Value = "AllocatedQty"
  joinWks.Cells(1, 3).Value = "InvoicedQty"
  joinWks.Cells(1, 4).Value = "InvoiceDate"
  joinWks.Cells(1, 5).Value = "ProcessDate"

  'loop through clinc data
  For i = 1 To cLo.ListRows.Count
    Container = cLo.ListColumns("Container").DataBodyRange(i).Value
    procDate = cLo.ListColumns("Process Date").DataBodyRange(i).Value

    If containerDict.exists(Container) Then
      allocQty = containerDict(Container)(0)
      invQty = containerDict(Container)(1)
      invDate = containerDict(Container)(2)

      'check date difference within 30 days
      If Abs(procDate - invDate) <= 30 Then
        j = joinWks.Cells(joinWks.Rows.Count, "A").End(xlUp).Row + 1
        joinWks.Cells(j, 1).Value = Container
        joinWks.Cells(j, 2).Value = allocQty
        joinWks.Cells(j, 3).Value = invQty
        joinWks.Cells(j, 4).Value = crDate
        joinWks.Cells(j, 5).Value = procDate
      End If
    End If
  Next i


Set containerDict = Nothing


End Sub

Excel Scripting Dictionary VBA - 区分重复项

需要求和的Table2的图片:

Excel Scripting Dictionary VBA - 区分重复项

解决方案

无法更新包含在字典中的数组-必须先将数组提取到变量中,然后更新它,最后用编辑后的版本替换存储在字典中的数组。

例如:

Dim tmp
'...
'...

If containerDict.exists(Container) Then
    tmp = containerDict(Container)  'copy to local variable
    tmp(0) = tmp(0) + allocQty      'update local copy
    tmp(1) = tmp(1) + invQty
    containerDict(Container) = tmp  'copy to dict
Else
    containerDict(Container) = Array(allocQty, invQty, invDate)
End If

你的数组只能捕获每个容器的第一个日期,所以这种方法最终会将所有日期相加…

对于从SharePoint或其他HTTP位置打开的文件,首先保存为本地临时副本进行了一些更改

例如:

Public Sub JoinandSum()

    Dim oCon As Object, rs As Object, conn As String
    Dim wb As Workbook, tblA As ListObject, tblB As ListObject, sql As String

    Set wb = ThisWorkbook
    Set tblA = wb.Worksheets("Input").ListObjects("Table1")
    Set tblB = wb.Worksheets("Input").ListObjects("Table2")

    conn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                        "Data Source=" & QueryPath(ThisWorkbook) & ";" & _
                        "Extended Properties=""Excel 12.0;"";"

    sql = " select a.Container, a.[Process Date], sum(b.[Invoice Qty]) as TotQty, " & _
          " min(b.[Invoice Date]) as MinInvDate, max(b.[Invoice Date]) as MaxInvDate " & _
          " from " & TableRef(tblA) & " a, " & TableRef(tblB) & " b " & _
          " where a.Container = b.Container and " & _
          " abs(a.[Process Date] - b.[Invoice Date])<30 " & _
          " group by a.Container, a.[Process Date]"

    Set oCon = CreateObject("ADODB.Connection")
    oCon.Open conn
    Set rs = oCon.Execute(sql)
    PutResults rs, wb.Worksheets("Input").Range("J1")

    rs.Close
    oCon.Close

End Sub

'When using ADO to query a workbook, figure out if it's opened from
'   an HTTP path, and if it is then make a temporary local copy as the data source
'Note: does not currently handle unsaved workbooks... 
Function QueryPath(wb As Workbook) As String
    Dim p As String
    p = wb.FullName
    If UCase(p) Like "HTTP*" Then
        p = Environ("temp") & "\" & wb.Name
        ThisWorkbook.SaveCopyAs p
    End If
    Debug.Print "Using file" & vbLf & p
    QueryPath = p
End Function

'return a string referencing a listobject, for use in sql
Function TableRef(lo As ListObject)
    TableRef = "[" & lo.Parent.Name & "$" & lo.Range.Address(False, False) & "]"
End Function

'Populate a range with the content of a recordset, including the field names
Sub PutResults(rs As Object, rng As Range)
    Dim f, i As Long
    For Each f In rs.Fields
        rng(1).Offset(0, i).Value = f.Name
        i = i + 1
    Next f
    If Not rs.EOF Then rng(1).Offset(1).CopyFromRecordset rs
End Sub

示例输入/输出:

Excel Scripting Dictionary VBA - 区分重复项

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程