How to integrate a MAX and IF statement into a FOR loop in VBA? - vba

Trying to include an if statement into the MAX function and create a FOR loop in VBA.
What I want the code to do is to return the MAX value from column B into a new column when the value in column A equals the value in column I. I also have more than 1,000 rows in the data set and so I need a loop.
Here is a screenshot of data set of the data set I'm working with:
When I execute the following code (max_no_loop) on my data set, I get the output that I am looking for. However, I want to loop over 1,000 rows and so I need I2 to be changing with each step of the integration.
Sub max_no_loop()
Range("K2").FormulaArray = "=MAX(IF(A:A=I2,B:B))"
End Sub
After thinking about it, I came up with the function below(max_loop) where I changed I2 to Cells(i, 9), however, when I run the function on my data, I get name errors (#NAME?) and don't get the desired outcome.
Sub max_loop():
Dim i As Integer
For i = 2 To 11
Cells(i, 11).FormulaArray = "=MAX(IF(A:A=Cells(i, 9),B:B))"
Next i
End Sub
Why am I unable to make the function work when I integrate it into a for loop?

You need to pull out the variable part completely like below:
Sub max_loop():
Dim i As Integer
For i = 2 To 11
Cells(i, 11).FormulaArray = "=MAX(IF(A:A=" & Cells(i, 9).Address & ",B:B))"
Next i
End Sub

You need to take your variable i outside the " of the formula.
Try the code below:
Sub max_loop():
Dim i As Integer
For i = 2 To 11
Cells(i, 11).FormulaArray = "=MAX(IF(A:A=Cells(" & i & ", 9),B:B))"
Next i
End Sub

Related

Naming the non-empty cells of a column as the previous column's values

So what I want is a button that when pressed will automatically name the right hand column cells the left hand column values, my code at the moment looks something like this,
Private Sub CommandButton1_Click()
Range("F3").Name = Range("E3")
Range("F4").Name = Range("E4")
Range("F5").Name = Range("E5")
Range("F6").Name = Range("E6")
End Sub
I'm new to using VBA and have looked around a little but couldn't find what I wanted to achieve. Just want a simple solution which can automatically do what my code already does without having to be specific about cell rows.
I imagine that there will be either a while or for loop to repeat over many rows and an if statement for the code not running if a cell is empty.
Basically I want the command to run something like below but don't quite know how to write it in excel VBA myself.
for j=3:100
if F(j) = non empty
F(j).name = E(j)
else end
next j
end
Image below shows the end result :
From your sample image this looks like it should work.
Option Explicit
Sub name_eff()
Dim rw As Long
With Worksheets("Sheet6")
For rw = 2 To Application.Min(.Cells(.Rows.Count, "E").End(xlUp).Row, _
.Cells(.Rows.Count, "F").End(xlUp).Row)
If Application.CountA(.Cells(rw, "E").Resize(1, 2)) = 2 Then _
.Cells(rw, "F").Name = .Cells(rw, "E").Text
Next rw
End With
End Sub

Excel range subtraction, overlooking errors in some cells possible?

I am having trouble figuring out how to subtract two ranges from each other, some cells in range H:H have "#N/A" while in range D:D there are no errors. I know in Excel it's a simple "=H2-D2" and drag that down but I'm in the process of recording a Macro and wanted to automate the subtraction as well. So far this is what I have:
Dim quantity1, quantity2, rIntersect, Qdiff, x As Range
Set quantity1 = Range("D:D")
Set quantity2 = Range("H:H")
Set rIntersect = Intersect(quantity1, quantity2)
For Each x In quantity1
If Intersect(rIntersect, x) Is Nothing Then
If Qdiff Is Nothing Then
Set Qdiff = x
Else
Set Qdiff = Application.Union(Qdiff, x)
End If
End If
Next x
Range("J2").Select
Dim lastRowJ As Long
lastRowJ = Range("A" & Rows.Count).End(xlUp).Row
Range("J2").AutoFill Destination:=Range("J2:J" & lastRowJ)
Place this procedure in a standard code module:
Public Sub Subtract()
[j2:j99] = [h2:h99-d2:d99]
End Sub
If you like how that works, I'm happy to embellish it so that it is not hard-coded for 98 rows only. Let me know.
UPDATE
Here is a version that will deal with any number of rows. It keys off of column D. So if there are 567 numbers in column D, then you will get 567 corresponding (subtracted) results in column J.
This assumes that the data start in row 2, and that there are no blank cells until the numbers in column D end.
If you are going to call this from the Macro Dialog then you should keep it Public. If on the other hand you are going to call it from another procedure in the same module, then you can make it Private.
Here is the enhanced solution:
Public Sub Subtract()
Dim k&
Const F = "iferror(h2:h[]-d2:d[],0)"
k = [count(d:d)]
[j2].Resize(k) = Evaluate(Replace(F, "[]", k + 1))
End Sub
Note that the routine now handles the errors and places a ZERO value in column J when the corresponding value in column H is an error. If you would prefer to have something other than a ZERO (like a blank for instance) when there are errors in column H, just let me know and I'll update to whatever you want.
UPDATE 2
Here is how to handle displaying blanks instead of zeroes:
Public Sub Subtract()
Dim k&
Const F = "iferror(if(h2:h[]-d2:d[]=0,"""",h2:h[]-d2:d[]),0)"
k = [count(d:d)]
[k2].Resize(k) = Evaluate(Replace(F, "[]", k + 1))
End Sub

using an input box to set up how many times a loop will run

I have a code that puts spaces in a column of numbers, so that each group of 6 numbers have 2 spaces between them, starting from the top of the sheet. After the groups of 6 there can be groups of 5, these need to have 3 spaces between them.
The groups of 6 always appear above the groups of 5.
I would like to have a code that asks how many groups of 6, then asks for how many groups of 5, then puts in the relevant spacing.
Sub MacroMan()
Dim x As Integer
x = 8
For i = 1 To CInt(InputBox("Run this many times:"))
'Range("H2").Paste
Application.CutCopyMode = False
Range("H&x:H&x+1").Insert Shift:=xlDown
'Range("H2:H110").Copy
x = x + 8
Next
End Sub
I've got the code to run now, but I get the following error.
Run-time error '1004'
Method 'Range of object'_'Global'failed
You can ask the user for their input and store the answer in a string. Then convert the string to an integer and use it to determine the number of loops.
sub AskUser
dim Answer as string
dim i as integer
dim Number as integer
Answer = Inputbox("Your text here")
Number = CInt(Answer) 'Note this will throw an error if you enter something that's not a numbeer
for i = 1 to Number
'code
next i
End sub
This should do the same thing, for the amount of times that you specify.
Important: Always run untested code on a copy of your data as executed code cannot be undone!
Sub SO()
Dim x As Integer, i As Integer
x = 8
Application.CutCopyMode = False
For i = 1 To CInt(InputBox("Run this many times:"))
Range("H" & x & ":H" & x + 1).Insert Shift:=xlDown
x = x + 8
Next
End Sub

MS Excel 2010 - VBA to lookup in one column a customer number and Tag the corresponding column with Yes or No

I have an extremely large dataset with customer numbers and we cannot just use a =IF(E3=160248, "YES", "NO") to tag a particular customer number of 160248 with YES or NO. Instead, I would like to use VBA code to lookup Customer_Number in column E and return a YES or NO in the corresponding row in Column AG, called Incorporated_160248. I have not done an If then clause in VBA, so I have no idea where to start. Please note, each month the data set can change. One month it could be 4,000 entries and the next 3,500, so that has to be dynamic. Any thoughts?
Sub TagTryco()
Dim CN As Integer, result As String
CN = Range("E:E").Value
If CN = 160248 Then
result = "YES"
Else
result = "NO"
End If
Range("AG:AG").Value = result
End Sub
I get a Compile error: Wrong number of arguments or invalid property assignment.
This CODE Works now:
Sub TagTryco()
Dim listLength
listLength = Worksheets("ILS_Import").Cells(Rows.Count, "E").End(xlUp).Row - 1
Dim i As Integer
For i = 2 To listLength + 2
If Worksheets("ILS_Import").Range("E" & i) = 160248 Then
Worksheets("ILS_Import").Range("AG" & i) = "Yes"
Else
Worksheets("ILS_Import").Range("AG" & i) = "No"
End If
Next
End Sub
To know how many entries you have:
dim listLength
listlength = Sheet1.Cells(Rows.Count, "E").End(xlUp).Row - 1 'I assumed column E, starting at row 2
You need to loop from row 2 to the row 2 + listLength, check the cell in column E, and check if it is equal to your number:
dim i as integer
for i = 2 to listLength + 2
If Range("E" & i) = 160248 Then
Range("AG" & i) = "Yes"
Else
Range("AG" & i) = "No"
End If
Next
If you wish to scan for different numbers you can adapt the code to use a value from a cell in which you enter that number, OR use an inputbox to enter the number you want to look for, or something else. This code was not tested.
If you want to use the column name you assigned instead of AG (which is safer) you can use something along the lines of:
= Range("Incorporated_160248")(i+1)
Instead, which gives the column with an offset of i. Should bring you to the right cell.

Looped If/Then Functions in Excel VBA

I'm just starting to learn Excel VBA and I'm running into problems with a particular exercise. Given a column of 20 randomly generated integers between 0 and 100 in a column, I want to write a VBA program that writes in the column next to it "pass" if the number is greater than or equal to 50 and "fail" if the number is less than 50.
My approach involved using a looping function from i = 1 to 20 with an If statement for each cell (i,1) which would write pass or fail in (i,2).
Sub CommandButton1_Click()
'Declare Variables
Dim score As Integer, result As String, i As Integer
'Setup Loop function, If/Then function
For i = 1 To 20
score = Sheet1.Cells(i, 1).Value
If score >= 60 Then result = "pass"
Sheet1.Cells(i, 2).Value = result
Next i
End If
End Sub
Could I get some insight into what I'm doing wrong?
Thanks in advance!
Try something like this...
Sub CommandButton1_Click()
'Declare Variables
Dim score As Integer, result As String, i As Integer
'Setup Loop function, If/Then function
For i = 1 To 20
score = Sheets("Sheet1").Cells(i, 1).Value
If score >= 60 Then
result = "pass"
Else
result = "fail"
End If
Sheets("Sheet1").Cells(i, 2).Value = result
Next i
End Sub
You need to properly specify the worksheet your working with like Sheets("Sheet1").Cells(...
Add an else clause to set result to fail when the value is less than 60. otherwise it never changes after the first 'pass'
Move the End if inside the for loop, immediately after the score check...
The correction with the least amount of changes is the following :
Sub CommandButton1_Click()
'Declare Variables
Dim score As Integer, result As String, i As Integer
'Setup Loop function, If/Then function
For i = 1 To 20
score = Sheet1.Cells(i, 1).Value
If score >= 60 Then
result = "pass"
Sheet1.Cells(i, 2).Value = result
End If
Next i
End If
End Sub
Keep in mind that, in VBA, variables are global to the function; not local to the loop. As it was mentionned, you could also have wrote something like :
result = ""
if score >= 60 then result = "pass"
sheet1....