VBA nestled Ifs with Or?

Joined
Jun 13, 2017
Messages
108
Hi, I've got this code that I need to make into one line or function (because of how many of the bastard I have excel won't run my macro).

Code:
If Range("C15").Value > 1 And Range("C15").Value <= 18 Then
    If (Range("D6").Value = "X" Or Range("D6").Value = "Y" Or Range("D6").Value = "Z") Then
        [B]If[/B] Range("C15").Value = Worksheets("Sheet2").Range("K1").Value And Worksheets("Sheet2").Range("L1").Value = "" Then
            If (Worksheets("Sheet2").Range("k1").Value <> Range("C21").Value Or Worksheets("Sheet2").Range("k1").Value <> Range("C27").Value Or Worksheets("Sheet2").Range("k1").Value <> Range("C33").Value Or Worksheets("Sheet2").Range("k1").Value <> Range("C39").Value Or Worksheets("Sheet2").Range("k1").Value <> Range("C45").Value) Then
            Call K1_2
            Call Remove_List
       [B] If [/B]Range("C15").Value = Worksheets("Sheet2").Range("K2").Value And Worksheets("Sheet2").Range("L2").Value = "" Then
            If (Worksheets("Sheet2").Range("k2").Value <> Range("C21").Value Or Worksheets("Sheet2").Range("k2").Value <> Range("C27").Value Or Worksheets("Sheet2").Range("k2").Value <> Range("C33").Value Or Worksheets("Sheet2").Range("k2").Value <> Range("C39").Value Or Worksheets("Sheet2").Range("k1").Value <> Range("C45").Value) Then
            Call K2_2
            Call Remove_List
...etc K3, K4, K5, K6
End If

I need the If functions in bold to be as though there's an OR between them.
So it's
Code:
If Range("C15").Value > 1 And Range("C15").Value <= 18 Then
    If (Range("D6").Value = "X" Or Range("D6").Value = "Y" Or Range("D6").Value = "Z") Then
        If1 ... condition ... then ... call macro 1
        or
        If2 ... condition ... then ... call macro 2
        or
        If3 ... condition ... then ... call macro 3
        ...etc

Thank you to everyone who will try to help me!
I've already learned so much from people on this forum, you guys are amazing.
 

Excel Facts

Format cells as date
Select range and press Ctrl+Shift+3 to format cells as date. (Shift 3 is the # sign which sort of looks like a small calendar).
So, I'm making no promises on this one, I had a hard time making sure I got all of the conditions involved, but you could try something like this. Side note, it doesn't have as much indenting as I would normally do so that it's a little easier to read.

Code:
Sub NestedIfs()
    Dim i as Integer, j as Integer
    
    Select Case [C15]
    Case 1 To 18
        Select Case [D6]
        Case "X", "Y", "Z"
            For i = 1 To 6
                With Sheets("Sheet2").Range("K" & i)
                If [C15] = .Value And .Offset(, 1) = "" Then
                    For j = 0 To 4
                    If .Value = Range("C" & (6 * j + 21)) Then
                        Application.Run "K" & i & "_2"
                        Call Remove_List
                        Exit For
                    End If
                    Next j
                End If
                End With
            Next i
        End Select
    End Select
End Sub
 
Upvote 0
Quick edit, just noticed that your first criteria is that it be > 1 and <= 18. I thought it could be 1 to 18. If you don't want the code to run if the value in cell C15 is exactly equal to 1, change the first Case statement to "Case Is > 1, Is <= 18".
 
Upvote 0
Quick edit, just noticed that your first criteria is that it be > 1 and <= 18. I thought it could be 1 to 18. If you don't want the code to run if the value in cell C15 is exactly equal to 1, change the first Case statement to "Case Is > 1, Is <= 18".

It can't be 1, no matter what. The minimum value to be chosen is 4.
Thank you so much for this!
May I just bother you to make sure that I've understood it, so as to be able to use it in the future without needing help as I've never used Dim before?

We first select C15 and if the number is between 1 and 18 we then move to the next line.
select D6 and if its value is X, Y or Z we move on.
Then I get a bit muddled up.

Code:
[COLOR=#333333]For i = 1 To 6[/COLOR]
i sets the if conditions for which "K" cell is to be used and then the same number for K macro is used.
j sets ... you've lost me there. Why are we multiplying by 6 and adding 21 to j? Obviously I know which C cells it's looking at, but I can't see how it's doing it.
And presumably you can have every letter from A to Z and have a condition associated with every letter?
Code:
[COLOR=#333333]Application.Run "K" & i & "_2"[/COLOR]
Why are we using Application.Run and not Call?

Next j & Next i just makes the macro run the number of times i and j are set to (maximum number so in this case 6 for i and 4 for j).
 
Last edited:
Upvote 0
Okay, so the Dim statement is used to declare a variable. Declaring a variable is considered to be best practice when writing VBA, or pretty much any code for that matter. Most languages won't even let you not declare one. VBA will allow it, but almost nobody does it. This is because when you don't declare a variable, VBA assigns it a data type of Variant, which while it can hold the greatest number of values out of all the data types, it is the least efficient, slowest, and usually results in errors unless you are intentionally declaring something as Variant (for instance, a lot of arrays tend to be declared as Variant). In this case, the data type I chose was Integer, which can hold signed numeric values up to ~32,000 in magnitude. Since I know that both i and j will never come close to hitting that cap, it's one of the most efficient data types I can use in this scenario. Additionally, it prevents me from accidentally trying to assign a value like a string of text to that variable. If I tried to say that i should = "test", VBA would error out with a type mismatch error. If you put the words "Option Explicit" at the very top of your code, VBA will require that you declare all of your variables before it will run the code. I personally do this with every single bit of code that I write because declaring variables has so many advantages. Look up Data Types and Variable Declaration for more information on this.

The For i = 1 to 6 loop is used because your original code indicated that you wanted to call 6 different routines. By using the variable i instead of hard-coding the values, I saved a lot of space and made the code easier to both read and debug. Additionally, I noticed that there are several instances where you referenced a cell with a row number of 1 to 6 in sequential order (specifically, K1:K6). By using the variable, I was able to replace the row number in those cell references with the variable, eliminating the need to call them 6 different times.

Regarding the secondary loop based on the variable j, I noticed that there was a pattern to the cells that you were comparing your "K1:K6" cells to. You started at cell C21, and then just moved 6 cells down. Instead of referencing 5 different cells, I decided to use the secondary loop to allow VBA to compare the "K" cell to the correct "C" cell, one cell at a time. The math is based on starting at cell C21. So 6 * 0 + 21 is 21, 6 * 1 + 21 is 27, 6 * 2 + 21 = 33, and so on. Instead of trying to compare the value in "K#" to all of the "C#" cells simultaneously, this does it sequentially. As soon as it finds that "K#" is not equal to any one of the "C#" cells, it quits comparing the "K#" cell and moves to the remainder of the code.

The reason I used Application.Run instead of Call is because that's the syntax required in order to run a procedure based on a variable name. If you type Application.Run, followed by a space, you'll see a list of parameters that you can pass into it. The first one is the name of the procedure you want to run, and the rest are arguments that you can pass to that procedure. You didn't indicate that you were passing any variables to a procedure, so the only argument I needed was the name of the procedure to be called. Since the name of the procedures follows a logical pattern, I was able to save a lot of space (and lessen the likelihood of errors) by using a variable name instead of hard-coding it 6 different times. However, since the next procedure you call after your K#_2 is named the same in both occurrences of your original code ("Remove_List"), it makes more sense to simply call that one by hard-coded name instead of assigning it to a variable. Variables are essential for good code, however, if you can get away with not using one, I would at least consider doing so whenever possible.

Finally, the Exit For statement after the call to the "Remove_List" procedure is there to prevent the j loop from attempting to repeat everything it just did in case it were to find another "C#" cell that did not equal the the "K#" cell. Everything after that is just there to close loops and shut the code down.

Couple little notes, the original Case statement has seemed weird to me from the beginning. Since you mentioned that the lowest value it can be is 4, I would just change it to Case 4 To 18 and be done with it, that's your safest bet. Also, the "If .Value = Range("C" & (6 * j + 21)) Then" line should actually be "If .Value <> Range("C" & (6 * j + 21)) Then". That was a typo in the original code. The final code should look like this:

Code:
Sub NestedIfs()
    Dim i As Integer, j As Integer
    
    Select Case [C15]
    Case 4 To 18
        Select Case [D6]
        Case "X", "Y", "Z"
            For i = 1 To 6
                With Sheets("Sheet2").Range("K" & i)
                If [C15] = .Value And .Offset(, 1) = "" Then
                    For j = 0 To 4
                    If .Value <> Range("C" & (6 * j + 21)) Then
                        Application.Run "K" & i & "_2"
                        Call Remove_List
                        Exit For
                    End If
                    Next j
                End If
                End With
            Next i
        End Select
    End Select
End Sub
 
Upvote 0
Again, thank you for everything you've done so far.
I also mentioned that there's more to the macro that I can just replace myself once I get a working variant of the code, but in my next batch the whole procedure runs for cell C21.
Will this work:

Code:
Dim i As Integer, j As Integer 
   Select Case [COLOR=#ff0000][C21][/COLOR]
    Case 1 To 18
        Select Case [D6]
        Case "X", "Y", "Z"
            For i = 1 To 6
                With Sheets("Sheet2").Range("K" & i)
                If [COLOR=#ff0000][C21][/COLOR] = .Value And .Offset(, 1) = "" Then
                    For j = 0 To 4
                    If .Value = Range([COLOR=#ff0000]"C15" & "C27" & "C33" & "C39" & "C45"[/COLOR]) Then
                        Application.Run "K" & i & "_2"
                        Call Remove_List
                        Exit For
                    End If
                    Next j
                End If
                End With
            Next i
        End Select
    End Select
 
Last edited:
Upvote 0
No, that won't work. When you use the & symbol, you're concatenating strings of text together. So if you were to run that code as is, it would attempt to see if the value in cell K1 equaled the value in cell C15C27C33C39C45, a completely non-existent cell. You need to set up a loop when you're handling multiple cells, there's really no other choice in the matter. Taking out the mathematical approach I gave you is really not a good idea. It looks to me like you're trying to do something with every 6th cell in the range C15:C45. If that's the case, you'd be better off setting up a loop to go through them. Something like this might work for you. Before you do much more, you need to do some research on loops in VBA. This is an article that's a good starting point. Loops, arrays, and variables are the heart and soul of coding. Using hard-codes just makes your life drastically more difficult than it has to be. You should also check out this video series from Wise Owl on YouTube. It's an excellent series of tutorials on how to get started in writing good VBA code in Excel.

Code:
Sub NestedIfs()
    Dim i As Integer, j As Integer, x As Integer
    
    For x = 15 To 45 Step 6
        Select Case Range("C" & x)
        Case 4 To 18
            Select Case [D6]
            Case "X", "Y", "Z"
                For i = 1 To 6
                With Sheets("Sheet2").Range("K" & i)
                    If Range("C" & x) = .Value And .Offset(, 1) = "" Then
                        For j = 0 To 5
                        If .Value <> Range("C" & (6 * j + 15)) And x <> (6 * j + 15) Then
                            Application.Run "K" & i & "_2"
                            Call Remove_List
                            Exit For
                        End If
                        Next j
                    End If
                End With
                Next i
            End Select
        End Select
    Next x
End Sub
 
Upvote 0

Forum statistics

Threads
1,215,352
Messages
6,124,455
Members
449,161
Latest member
NHOJ

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top