简体   繁体   English

在Excel VBA中使用'For Each'循环和'If'语句时出错

[英]Error in using 'For Each' loop and 'If' statement in excel vba

Excel VBA - Error in using 'For Each' loop and 'If' statement. Excel VBA-使用“ For Each”循环和“ If”语句时出错。

I have an excel workbook; 我有一本Excel工作簿; which has two sheets: 有两张纸:

The first sheet is: 'Jurisdictions' Which has three columns: 第一页是“司法管辖区”,其中包含三列:

Country (Column B), State (Column C) and City (Column D) 国家(B栏),州(C栏)和城市(D栏)

This sheet has single entry for each city. 此工作表每个城市都有一个条目。

But, as each city is listed on separate row, the names of state and country(To which cities belong) can get repeated on multiple rows. 但是,由于每个城市都在单独的行中列出,因此州和国家(城市所属)的名称可以在多行中重复。

For Ex: 例如:

Col B   |  Col C   |   Col D   |
--------------------------------
U.S.    | New York |  Buffalo  |
U.S.    | New York | Manhattan |

(These are my two rows) (这是我的两行)

I have another sheet: Sheet1; 我还有另一张纸:Sheet1;

Here also I have same three columns; 这里我也有相同的三列; (and 20 some other columns) (以及其他20列)

These three columns I shall validate with three columns in 'Jurisdictions' sheet. 我将使用“管辖权”表中的三列来验证这三列。 (Only few 'Jurisdictions' are listed in Sheet1; and those can be in any order and can be for any country) (Sheet1中仅列出了很少的“管辖区”;这些管辖区可以按任何顺序排列,并且可以适用于任何国家/地区)

The validation Rules are: 验证规则是:

1) For Country 1)国家

  • Country name should be a single value only. 国家/地区名称只能是一个值。
  • Should match with name under 'Country' column in Jurisdiction sheet. 应与管辖权表中“国家/地区”列下的名称匹配。
  • Cases should be neglected (Uppercase/Lowercase) 案件应忽略(大写/小写)

2) State 2)状态

  • Can have one or Multiple values separated only with semicolon (To separate those values with semicolon I have written a different code and it works fine) 可以有一个或多个仅用分号分隔的值(要用分号分隔这些值,我编写了不同的代码,效果很好)
  • The entry in this cell even can be 'All' 该单元格中的条目甚至可以是“全部”
  • All the state names should match with states listed under 'state' column of Jurisdiction sheet. 所有州名称应与“管辖权”表“州”列中列出的州相匹配。 (If multiple entries are listed; those should be first separated based on delimeter - semicolon and then to be compared) (如果列出了多个条目,则应首先根据分号(分号)将其分开,然后进行比较)
  • Cases should be neglected (Uppercase/Lowercase); 案件应忽略(大写/小写); Extra spaces before and after state names should be trimmed. 状态名称前后的多余空格应修剪。

3) City 3)城市

  • Can have one or Multiple values separated only with semicolon. 只能有一个或多个用分号分隔的值。
  • The entry in this cell can be 'All' also. 该单元格中的条目也可以是“全部”。
  • All the city names should match with cities listed under 'City' column of Jurisdiction sheet. 所有城市名称应与“管辖权”表中“城市”列下列出的城市相匹配。 (If multiple entries are listed; those should be first separated based on delimeter - semicolon and then to be compared) (如果列出了多个条目,则应首先根据分号(分号)将其分开,然后进行比较)
  • Cases should be neglected (Uppercase/Lowercase); 案件应忽略(大写/小写); Extra spaces before and after state names should be trimmed. 状态名称前后的多余空格应修剪。

I have the following code which validates Countries, States and Cities correctly. 我有以下代码可以正确验证国家,州和城市。 (linguistically - spelling.) (从语言上讲-拼写。)

ie

Col B   |  Col C   |       Col D        |
-----------------------------------------
U.S.    | New York | Buffalo            |
U.S.    | New York | Manhattan; Buffalo |
India   | Karnataka| Bangalore          |

Also it validates the hierarchy correctly. 此外,它还可以正确验证层次结构。

Dim nLastRow As Long
Dim nLastRowSheet2 As Long
Dim rngFnder As Range
Dim strFndAddress As String

Dim stString As String
Dim stArray() As String

'Get the last row
'Dim lastRow As Integer
nLastRow = Sheets("Sheet1").Cells(Rows.Count, 2).End(xlUp).Row
nLastRowSheet2 = Sheets("Jurisdictions").Cells(Rows.Count, 2).End(xlUp).Row

Dim c As Range
Dim d As Range
Dim e As Variant

'Turn screen updating off to speed up macro code.
'User won't be able to see what the macro is doing, but it will run faster.
Application.ScreenUpdating = False

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
stString = c
stArray() = Split(stString, ";")
For Each e In stArray()
    e = Trim(e)

    strFndAddress = ""
    On Error Resume Next

        Set rngFnder = Sheets("Jurisdictions").Range("D2:D" & nLastRowSheet2).Find(e)

        If rngFnder Is Nothing And c <> "All" Then
            c.Interior.Color = vbRed

        Else
            strFndAddress = rngFnder.Address
            Do
                If c.Offset(, -1) = rngFnder.Offset(, -1) And c.Offset(, -2) = rngFnder.Offset(, -2) Then
                    strFndAddress = ""
                    Exit Do
                Else

                    Set rngFnder = Sheets("Jurisdictions").Range("D2:D" & nLastRowSheet2).FindNext(rngFnder)

                End If
            Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress
        End If

        If rngFnder.Address = strFndAddress Then
            c.Interior.Color = vbRed
        End If
    On Error GoTo 0
    Set c = Nothing
    strFndAddress = ""
Next
Next

Now I have other requirements 现在我还有其他要求

  • There can be multiple states listed in 'state' cell separated only with semicolon. 在“状态”单元格中可以列出仅用分号分隔的多个状态。
  • If multiple states are listed under state; 如果在状态下列出了多个状态; then the adjacent cell for City should( mandatorily) have value "All" only. 那么City的相邻单元格应该(强制)仅具有值“ All”。 (As if multiple states are listed then the above code can't validate the hierarchy correctly) (就像列出了多个状态一样,以上代码无法正确验证层次结构)
  • State cell may have value as "All" (ie All states; no state listed separately) 状态单元格的值可能为“所有”(即所有状态;没有单独列出的状态)
  • If state cell has value "All" then the adjacent city cell should ( mandatorily) have value "All" only. 如果状态单元格的值为“全部”,则相邻的城市单元格(强制性)应仅具有值“全部”。
  • There can be cases where a single state value is listed under State, but still adjacent city cell can have value "All" 在某些情况下,“州”下会列出一个州的值,但相邻的城市单元格仍可以具有“全部”值

To implement the above requirements I added following code 为了实现上述要求,我添加了以下代码

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
        If c.Offset(, -1) = "All" And c = "All" Then
            c.Interior.Color = vbWhite
        End If
Next

and... 和...

For Each c In Worksheets("Sheet1").Range("D2:D" & nLastRow)
    If c = "All" Then
    stString = c.Offset(, -1)
    stArray() = Split(stString, ";")
    End If
        For Each e In stArray()
        e = Trim(e)
        strFndAddress = ""

        On Error Resume Next

        Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).Find(e)

        If rngFnder Is Nothing And e <> "All" Then
            'c.Interior.Color = c.Interior.Color (Do Nothing)
        Else
            strFndAddress = rngFnder.Address
            Do
            If c.Offset(, -2) = rngFnder.Offset(, -2) Then
                    strFndAddress = ""
                    c.Interior.Color = vbWhite
                    Exit Do
            Else
                    Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).FindNext(rngFnder)

            End If
            Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress
        End If

        If rngFnder.Address = strFndAddress Then
        'c.Interior.Color = c.Interior.Color (Do Nothing)
        End If
        On Error GoTo 0
        Set c = Nothing
        strFndAddress = ""

    Next
 Next

The last code is little erroneous. 最后的代码几乎没有错误。

If the 'State' cell has a single state and adjacent 'City' cell has value "All" :it validates it correctly. 如果“状态”单元格具有单个状态,而相邻的“城市”单元格具有值“全部”:它将正确验证它。

But; 但; If 'State' cell has multiple states separated with a semicolon; 如果“状态”单元格具有以分号分隔的多个状态; and adjacent 'City' cell has value "All" then code do not validate it correctly. 并且相邻的“城市”单元格的值为“全部”,则代码无法正确验证它。

Can anyone help me where I am wrong? 谁能帮助我我错了? and also how I can increase the performance of code... 以及如何提高代码的性能...

Looking at your code, it seems you are making this really really complicated, where it does not really have to be. 查看您的代码,看来您正在使它真的变得非常复杂,而实际上并不一定要这样做。

If I gather this correctly, users will be entering data in your excelworkbook and you want to make sure they do this correctly, following some rules. 如果我正确收集了这些信息,则用户将在excelworkbook中输入数据,并且您要确保他们遵循某些规则正确地执行了操作。 If they break the rules you will color the cell red. 如果他们违反了规则,您将单元格涂成红色。

The easier and faster way to do this is use the conditional formatting built in to excel. 更简单,更快捷的方法是使用Excel内置的条件格式。 This will also allow you to split your code, and only check data that has actually changed: so no need to loop through all the cells. 这也将允许您拆分代码,并且仅检查实际已更改的数据:因此无需遍历所有单元格。

Quick example: 快速示例:

  • If multiple states are listed under state; 如果在状态下列出了多个状态; then the adjacent cell for City should( mandatorily) have value "All" only. 那么City的相邻单元格应该(强制)仅具有值“ All”。 (As if multiple states are listed then the above code can't validate the hierarchy correctly) You state that multiple states would be colon-separated. (就像列出了多个状态一样,上面的代码无法正确验证层次结构)您声明多个状态将用冒号分隔。 So you need a rule that states: if my cell under column B contains a ";" 因此,您需要一条规则指出:如果B列下的单元格包含“;” then my cell under column B must contain "All". 那么我在B列下的单元格必须包含“全部”。 If this is not so, I want to color the cell under column C red. 如果不是这样,我想将C列下的单元格涂成红色。

To add this rule you select the first cell of column C, and you choose "Conditional Formatting" from the Home tab in Excel;s ribbon. 要添加此规则,请选择C列的第一个单元格,然后从Excel功能区的“主页”选项卡中选择“条件格式”。 Then you create a new rule, and choose to use a formula to determine which cells to format. 然后,您创建一个新规则,并选择使用公式来确定要格式化的单元格。 The formula you need is "=NOT(ISERROR(FIND(";";B1)))" Then you set the format to red Fill and save the rule. 您需要的公式是“ = NOT(ISERROR(FIND(“;”; B1)))”然后将格式设置为红色填充并保存规则。

This rule will now work for the first row, in order to make it work for the entire column, you can go to manage rules and adjust the "applies to" field to $C:$C or you can copy the formatting to the cells you want to use. 现在,此规则将适用于第一行,为了使其适用于整个列,您可以去管理规则并将“适用于”字段调整为$ C:$ C,也可以将格式复制到单元格中您要使用。

You can create a Conditional formatting rule for every rule you have on your workbook. 您可以为工作簿上的每个规则创建条件格式设置规则。 You can also code functions for specific rules that you can not express easily in Excel's native funtions. 您还可以为无法在Excel的本机功能中轻松表达的特定规则编写函数代码。

This will make your checks simple and easier to maintain, but it will also make your user feedback instantanious: as soon as they enter a value, the rules are applied. 这将使您的检查变得简单且易于维护,但也将使您的用户反馈迅速:一旦输入值,规则就会被应用。

First, let me state that the approach in my previous answer can easily be applied to a workbook containing data, and is the best way forward. 首先,让我指出,我先前的答案中的方法可以轻松地应用于包含数据的工作簿,并且是最好的方法。

But as you ask for input on your code, maybe you should look at the second part of your else. 但是,当您要求输入代码时,也许您应该看一下其他代码的第二部分。 If State has multiple states, and the state can be found on the jurisdictions tab, your code will go to the following else block: 如果州有多个州,并且可以在“管辖区”选项卡上找到州,则您的代码将转到以下else块:

strFndAddress = rngFnder.Address
Do
    If c.Offset(, -2) = rngFnder.Offset(, -2) Then
        strFndAddress = ""
        c.Interior.Color = vbWhite
        Exit Do
    Else
        Set rngFnder = Sheets("Jurisdictions").Range("C2:C" & nLastRowSheet2).FindNext(rngFnder)
    End If
Loop While Not rngFnder Is Nothing And rngFnder.Address <> strFndAddress

This block does nothing with the "All" value. 该块对“ All”值不执行任何操作。

Also, this line confuses me (more than once): 另外,这一行使我感到困惑(不止一次):

c.Interior.Color = c.Interior.Color

Other tips you might enjoy: 您可能会喜欢的其他技巧:

  • rename your variables so you can actually read what they represent: "cityName" instead of "e" and cityCell instead of "c" makes a lot of difference. 重命名变量,以便您可以实际读取它们代表的含义:“ cityName”代替“ e”,cityCell代替“ c”产生很大的不同。
  • Use the UsedRange of a worksheet to determine the last row and column. 使用工作表的UsedRange确定最后一行。 It is faster and more stable than using the End functions. 它比使用End函数更快,更稳定。
  • Do not use On Error Resume Next. 不要使用On Error Resume Next。 This will surpress any errors and make it very hard to find any errors that occur. 这将掩盖所有错误,并且很难发现发生的任何错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM