【问题标题】:Excel VBA code modification so only alert me once for same itemExcel VBA 代码修改,因此仅针对同一项目提醒我一次
【发布时间】:2013-06-13 16:49:40
【问题描述】:

我管理一个合同日志,其中列出了我公司的所有合同以及生效日期和到期日期。

我编写了 VBA 代码,当任何一份合同即将到期时都会提醒我;将出现一个消息框,告诉我“承运人的合同#即将到期”。 (请参阅下面的代码)。

但是,由于每份合同有不同的修订,相同的合同编号可能会在电子表格中多次列出。如果一份合同即将到期,代码会多次通知我。

如何修改我的代码,以便它只针对相同的合同号提醒我一次?

A 栏是承运人名称,B 栏是合同编号,C 栏是修订编号,G 栏是每份合同的到期日期。

如果我说得不够清楚或需要更多信息,请告诉我。

Private Sub Workbook_Open()
Dim rngC As Range
With Worksheets("NON-TPEB SC LOGS(OPEN)")
    For Each rngC In .Range(.Range("G5"), .Cells(.Rows.Count, "G").End(xlUp))
        If rngC.Value > Now And (rngC.Value - Now) < 7 Then
            MsgBox .Cells(rngC.Row, 1).Value & "'s " & _
                   .Cells(rngC.Row, 2).Value & " is expiring!!"
        End If
    Next rngC
End With
End Sub

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    我会使用Scripting.Dictionary 来跟踪已检查的合同编号。这就是你可以实现它的方式。

    完成逻辑测试后(If rngC.Value &gt; Now And...) 检查字典中是否存在contractNum。这就是这一行的作用:

    If Not checkedDict.Exists(contractNum) Then

    • 如果计算出True,那么合约还没有被检查,所以我们将它添加到字典中,并显示消息框。
    • 如果计算结果为False,则合同确实存在于 字典,所以无能为力,因为用户已经 通知即将到期的合同。

    这是完整的代码(未经测试):

    Private Sub Workbook_Open()
    'Requires reference to Microsoft SCripting Runtime
    ' or, simply declare the scripting obects as generic "Object" variables.
    
    Dim checkedDict As Scripting.Dictionary
    'Dim checkedDict as Object  '## Use this line (andcomment out the preceding line if you cannot enable the library reference to Scripting Runtime
    
    Dim contractNum As String
    Dim carrierName As String
    Dim rngC As Range
    
    Set checkedDict = CreateObject("Scripting.Dictionary")
    
        With Worksheets("NON-TPEB SC LOGS(OPEN)")
            For Each rngC In .Range(.Range("G5"), .Cells(.Rows.Count, "G").End(xlUp))
                carrierName = .Cells(rngC.Row, 1).Value
                contractNum = .Cells(rngC.Row, 2).Value
    
                If rngC.Value > Now And (rngC.Value - Now) < 7 Then
                    If Not checkedDict.Exists(contractNum) Then
                        checkedDict.Add contractNum, carrierName
                        MsgBox carrierName & "'s " & _
                           contractNum & " is expiring!!"
                    Else:
                        ' this contract# already exists, so, do nothing
                        ' because the user was already informed.
                    End If
                End If
    
            Next rngC
        End With
    
        set checkedDict = Nothing
    End Sub
    

    以上代码需要引用 Microsoft Scripting Runtime Library,或者,只需 Dim checkedDict as Object

    【讨论】:

    • 如何引用 Microsoft Scripting Runtime Library。我尝试将checkedDict设置为对象,发生运行时错误
    • 从 VBE 中,工具 |参考,然后向下滚动,直到找到“Microsoft Scripting Runtime”(screenshot)。如果仍然有错误,请告诉我是哪一行导致错误以及错误消息的内容。
    • 为了在不引用脚本运行时的情况下工作,您需要使用Dim checkedDict As Object 声明并使用Set checkedDict = CreateObject("Scripting.Dictionary") 进行分配。否则 Excel 不知道您要使用字典。
    • 仍然错误,错误消息显示 Run-time erroe "91" : Object variable with block variable not set with "If Not checkedDict.Exists(contractNum) Then" 突出显示。
    • @user2483063 我之前的评论(部分)是错误的,因为我没有注意代码。您需要创建 Dictionary 对象,有两种方法:(1)Dim checkedDict As New Scripting.Dictionary,和(2)Dim checkedDict As Scripting.DictionaryDim checkedDict As Object 后跟Set checkedDict = CreateObject("Scripting.Dictionary")。如果您有参考,则两个系统都可以工作,否则只有后者。前者最好,因为 Excel 知道您正在处理什么对象。
    【解决方案2】:

    我总是使用AlreadyChecked 字符串变量来跟踪已处理的内容。

    在循环中添加这样的检查:

    Dim AlreadyChecked As String
    
    AlreadyChecked = "@"
    If Instr(AlreadyChecked, "@" & ValueToCheck & "@") = 0 Then
      AlreadyChecked = AlreadyChecked & ValueToCheck & "@"
      ... do your stuff ...
    End If
    

    【讨论】:

    • 我可能会使用字典,但这是解决问题的一种巧妙方法。不确定它是 100% 的假阳性证明(例如,包含你的分隔可能会引发部分匹配吗?),但我认为它在绝大多数情况下都会起作用。 +1
    • 当您确定数据中没有出现分隔符时,这是一个好方法。我遇到的唯一问题是当字符串连接数千次时它会变慢。您将如何在 VBA 中使用字典?
    • 看到我的回答,因为你问:) 它应该总是比存储/比较长字符串更快。
    • 谢谢。在 VBA 中使用字典的好技巧,我一直想念它们!我会坚持使用我的系统来处理快速和肮脏的情况,并记住 Scripting.Dictionary 来处理更严重的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多