【问题标题】:Updating monthly data, required to insert a new row if data does not exist更新每月数据,如果数据不存在则需要插入新行
【发布时间】:2020-09-02 03:56:09
【问题描述】:

对于excel中的上表(请参考图片),我正在构建一个宏来自动更新每月余额。我有 1 月到 12 月的数据,为简单起见,我假设只有 1 月和 2 月的数据。

通过使用VLOOKUP,我可以将二月余额附加到一月余额的相邻列。但是,我担心的是每个月现有客户的新帐户(例如Cell F8 中的客户B 2345675555),因为VLOOKUP 会简单地忽略它。我需要复制新客户 ID 的数据并将它们粘贴到现有表下的新行中。请注意,每个客户的帐户数量只会增加。非常感谢您能给我提供一个解决方案(可以通过 VBA 宏实现)。

【问题讨论】:

  • 对不起,我知道这对解决手头的问题没有帮助,但是这个数据结构看起来真的很危险,我假设这些数据将被汇总到其他地方以供查看。是否可以将这些数据收集到一个表中,其中有一列代表月份?
  • @mpn275 感谢您的回复。在实际情况下,每个月的余额都存储在同一工作簿中的不同工作表中。例如,Worksheets("Jan") 中一月份的数据。而且我还有一张母版表可以得到最终结果。
  • 好的,看起来你已经得到了答案,但如果可能的话,你应该看看你是否可以在一张表中收集所有数据,其中包含“Id”、“Name”、“Month”列', 'Amount',其中 Amount 将是余额的变化(即当月所有事件的总和)。然后运行总计给出任何月份的余额。一般来说,数据结构越好,需要的宏就越少。

标签: excel vba excel-formula


【解决方案1】:

实际上,我认为您的“Jan”工作表是您的“主”工作表,其标题行中将包含所有月份名称,并且这些也将是您所在的同一工作簿中的工作表名称想要导入余额。

因此,我想到了您可以双击“主”表上的月份名称(名称无关紧要)并从您单击的名称的表中导入余额(名称​​必须完全匹配) 到您单击的列中。下面的代码正是这样做的。就像在 VLOOKUP 中一样,该表列出客户名称的顺序无关紧要。但新名称将添加到底部。在下一次运行之前,您可以对它们进行不同的排序。与使用 VLOOKUP 时不同,工作表之间没有永久链接。这是代码。

Option Explicit

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, _
                                        Cancel As Boolean)
    ' 084
    
    Const TriggerRow    As Long = 1         ' change to suit
    
    Dim TabName         As String           ' worksheet name to update from
    Dim WsS             As Worksheet        ' data source: Tabname
    
    With Target
        If .Row = TriggerRow Then           ' skip if row is different
            TabName = .Value
            If Len(TabName) Then            ' if the clicked cell isn't blank
                On Error Resume Next
                Set WsS = Worksheets(TabName)
                If Err Then
                    MsgBox "The worksheet """ & TabName & """ hasn't been set up yet.", _
                           vbInformation, "Invalid tab name"
                Else
                    Application.ScreenUpdating = False      ' this is faster
                    TransferBalances Target, WsS
                    Application.ScreenUpdating = True
                End If
            End If
            Err.Clear
            Cancel = True
        End If
    End With
End Sub

Private Sub TransferBalances(Target As Range, _
                             WsS As Worksheet)
    ' 084
    
    ' the same columns are used in both the Master and all Source sheets
    ' columns need not be positioned in numeric sequence (1 = "A", 2="B" etc)
    Const NameClm   As Long = 1         ' specify the column where the Client names are
    Const IdClm     As Long = 2         ' specify the column where the Client IDs are
    Const BalClm    As Long = 3         ' specify the column where the balance are
    
    Dim IdRng       As Range            ' existing IDs in "Master" sheet
    Dim SrcRng      As Range            ' cell range containing source data
    Dim Src         As Variant          ' value of SrcRng (for faster access)
    Dim R           As Long             ' loop counter: Rows
    Dim Rt          As Long             ' target row
    
    With Target.Worksheet
        Set IdRng = .Range(.Cells(1, IdClm), .Cells(.Rows.Count, IdClm).End(xlUp))
        ' the range will not be extended to include added items
    End With
    
    With WsS
        R = .Cells(.Rows.Count, IdClm).End(xlUp).Row        ' last used row (IdClm)
        ' row 2 is the first row with data to be transferred
        ' copy all columns from A to the last one used in row 1
        Set SrcRng = .Range(.Cells(2, 1), _
                            .Cells(1, .Columns.Count).End(xlToLeft).Offset(R - 1))
    End With
    Src = SrcRng.Value
    
    For R = 1 To UBound(Src)
        On Error Resume Next
        Rt = WorksheetFunction.Match(Src(R, IdClm), IdRng, 0)
        With Target.Worksheet
            If Err Or (Rt = 1) Then             ' disallow match in header row
                Rt = .Cells(.Rows.Count, IdClm).End(xlUp).Row + 1
                .Rows(Rt - 1).Copy
                .Rows(Rt).Insert Shift:=xlDown  ' copy formats from above
                Application.CutCopyMode = False
                .Cells(Rt, NameClm).Value = Src(R, NameClm)
                .Cells(Rt, IdClm).Value = Src(R, IdClm)
            End If
            .Cells(Rt, Target.Column).Value = Src(R, BalClm)
        End With
    Next R
    Err.Clear
End Sub

由于代码响应双击事件,它必须安装在主工作表的代码模块中。这个位置是必不可少的,因为在您的工作簿中的其他任何地方都不会注意到双击。只有将代码粘贴到该模块中,您才能享受承诺的自动化。

【讨论】:

  • 很高兴你喜欢它@czxc。然而,英雄们的答案被标记为“已选择”:-)
猜你喜欢
  • 2015-12-17
  • 2014-05-05
  • 2016-11-19
  • 2017-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
相关资源
最近更新 更多