Copying a Range from one Sheet to Another with Variables - excel

This is my code:
If AssociateNameArray(ArrayLoop) = ThisWorkbook.Sheets(i).Cells(3, CompareCounter).Value Then
If i = 2 Then
Sheets(i).Range(CompareCounter & "6:" & CompareCounter & "12").Copy Destination:=Sheets(1).Range((ArrayLoop + 4) & "2")
Sheets(i).Range(CompareCounter & "14:" & CompareCounter & "28").Copy Destination:=Sheets(1).Range((ArrayLoop + 4) & "9")
CompareCounter = CompareCounter + 1
End If
End If
It gives
1004 error
Basically I am walking through a set range where CompareCounter is the column number. (stupid name, I know) I have names in an array and it is comparing the values of the array to cells in a row and when it finds a match it copies a set range back to the person's column on the main page at a certain row. The person's column number should be ArrayLoop + 4, as they start in column E. I will walk through each sheet (i) and when I find matches I will take the ranges from that sheet and copy it to the main page.

This is what causes the 1004 error: Range((ArrayLoop + 4) & "2")
If ArrayLoop is 4, then once it is evaluated to something, then it looks like this Range(52) and this is no valid range, returning 1004.
In general, try to debug the code step-by-step with F8 and always look at the values of the variables.

Related

Convert part of Formula from Relative to Absolute Reference

Originally I wanted to change parts of a formula in every 82th row where the formula looks like
=SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;"<="&$A7382;A:A;">"&A7383)
So I wanted to change each formula for a thousand of rows from (...;$BI7382;...;"<="&$A7382;...) to:
(...;$BI$7382;...;"<="&$A$7382;...) where $7382 is always one row before the row that includes the formula above.
So the next row with this formula would be $7464 where my code should change from (...;$BI7463;...;"<="&$A7463;...) to:
(...;$BI$7463;...;"<="&$A$7463;...) and so on.
I had success with your code
For i = 7383 To Cells(Rows.Count, 1).End(xlUp).Row Step 82
Cells(i, 1).Formula = Replace(Cells(i, 1).Formula, "$BI" & i - 1, "$BI$" & i - 1)
Cells(i, 1).Formula = Replace(Cells(i, 1).Formula, "$A" & i - 1, "$A$" & i - 1)
But: There is a single column which has cells with
=SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;<="&$A7382;A:A;">"&$A7383)
where the last value has changed from
">"&A7383to">"&$A7383
such that the last two values both have absolute column references
Because the code finds two values with $A... the replace function does not work properly
(Cells look like =SUMIFS($BJ:$BJ;$BO:$BO;$BI7382;$A:$A;"<="&$A7382;A:A;">"& after the code is executed
The problem is that the string "SUMIFS($BI" & cl.Row - 1 does not exist in your formula, so nothing gets replaced. Try the following line, it should work.
cl.Formula = Replace(cl.Formula, "$BI" & cl.Row - 1, "$BI$" & cl.Row - 1)
Now, it is better to declare the variable i as an Integer since it is used as a row index, and row indexes are integers. That way we avoid inaccuracy of Double (i.e. floating-point) arithmetic.
Dim i As Integer
In the For loop, i starts at 7383 and is incremented by steps of 81. This is good. However, i is not used anywhere in the replace statement. But the For Each loops through all rows of column O. The For Each is not needed. You can access cells in column O with Cells(i, 15). So the For loop becomes:
For i = 7383 To Cells(Rows.Count, 1).End(xlUp).Row Step 81
Cells(i, 15).Formula = Replace(Cells(i, 15).Formula, "$BI" & i - 1, "$BI$" & i - 1)
Next i
The upper bound value of i in the For loop is determined by the contents of column A. If column A has fewer rows than column O, then some replacements may be missed.

Excel VBA Trying to write a "MAX" formula to Cells with different Ranges with For-Loop

I am trying to make VBA write a formula into different cells that will find the maximum value for a Range decided by some variables. My variables I and J are (numbers/Integers).
Here is my code.
Sub AddMAX()
Dim I As Integer
Dim J As Integer
Dim L As Integer
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
For L = 5 To 4 + J
Worksheets(1).Cells(L, 4 + I).Formula = "=" & Max(Range(Cells(L, 4), Cells(L, 3 + I)))
Next L
End Sub
Have tried to re-write the second part (part behind the equal sign) several times. Usually I get the message Compile error: Sub or Function not defined and it marks the "Max". I thought Max (also tried with big letters) was an in-built function like SUM and so on.
I'm trying to make it write an Excel formula like this into the cells:
For I=2 and J=3:
Cell F5: =MAX(D5:E5)
Cell F6: =MAX(D6:E6)
Cell F7: =MAX(D7:E7)
i.e. I want a formula in the cells like I had wrote it in the cells manually to calculate max value, so that if the value in Cells D5, to D7 and E5 to E7 change, the new max value will be found without any scripts having to run.
Let me know if something is unclear.
You should not be putting Range and Cells in a formula string, they mean nothing to the Excel formula engine. You need the Address of the cells:
Dim I As Long
Dim J As Long
Dim L As Long
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
L = 5
With Worksheets(1)
.Range(.Cells(L, 4 + I), .Cells(4 + J, 4 + I)).Formula = "=MAX(" & .Cells(L, 4).Address(False, False) & ":" & .Cells(L, I + 3).Address(False, False) & ")"
End With
The formula is actually the same for all cells, which is why it is possible to assign it in one assignment for the entire range. It looks different in the A1 reference notation, but if you switch to R1C1 in the Excel settings, you will see they are the same. Which also means it is easier to create that formula using the R1C1 notation in the first place:
Dim I As Long
Dim J As Long
Dim L As Long
I = InputBox("Number of columns to check max value")
J = InputBox("Number of Rows to add formula inn and find max value of that row")
L = 5
With Worksheets(1)
.Range(.Cells(L, 4 + I), .Cells(4 + J, 4 + I)).FormulaR1C1 = "=MAX(RC[-" & I & "]:RC[-1])"
End With
But it would appear to me that you should instead use the Excel interface the intended way. Select the cells in which the MAX formula should be. Keeping the entire range selected, put the MAX formula into any of its cells as if you were creating it for just that cell, but instead of pressing Enter, press Ctrl+Enter.
You have to be careful to distinct between the part that is seen by VBA and the final formula.
If you write
Worksheets(1).Cells(L, 4 + I).Formula = "=" & Max(Range(Cells(L, 4), Cells(L, 3 + I)))
Max (and all the following stuff) is seen by the VBA-interpreter, not Excel. But there is no Max-function, and you get an (compiler)-error.
If you write
Worksheets(1).Cells(L, 4 + I).Formula = "=Max(Range(Cells(L, 4), Cells(L, 3 + I)))"
the VBA-interpreter sees the whole stuff as a string. It cannot take care about variables like L or I because is doesn't see them. So you end up with a formula that is exactly like you write it - and Excel (not VBA) will show you an error because it doesn't understand L or I.
What you need is a statement (in VBA) that creates a string that contains the actual values of your variables, and assign it to the cell.formula. I strongly advice that you first assign this to a string variable - it makes debugging much easier:
Dim formula As String
formula = "=Max(Range(Cells(" & L & ", 4), Cells(" & L & ", 3 + " & I & ")))"
Debug.Print formula
Worksheets(1).Cells(L, 4 + I).Formula = formula
Update: Sorry, I haven't looked to the content of the formula at all, of course the Range and Cells-objects are VBA objects. What you need in your formula is the address of the range, so change the line to
formula = "=MAX(" & Range(Cells(L, 4), Cells(L, 3 + i)).Address & ")"
Now VBA will create a Range and put the address into the formula string.

Excel VBA code inputing the correct numbers

For innerLoop = 0 To addRowOffset = 1
Range("C" & countRow & ":" & "C" & (countRow + addRowOffset)).Value = _
ThisWorkbook.Sheets("Template").Range("B" & (4 + innerLoop)).Value
Next
So I have this code which is supposed to take some rows that I inserted into a sheet, and fill Colum "C" with the a range of strings from the "Template" sheet. However, all it does it put one string and copy over and over again into the cells. How, do I get this to put the entire range of strings into the other sheet?
I'm willing to provide more of the code, or information if needed.
You seem to be putting the same value from the Template worksheet into all of the Range("Cx") cells at once. You put different values in but you replace all of the Range("Cx") cells each time during the loop.
For innerLoop = 0 To addRowOffset
Range("C" & countRow + innerLoop).Value = _
Sheets("Template").Range("B" & (4 + innerLoop)).Value
Next innerLoop
That should put a different value into a different cell for each iteration of the loop.
Note the change in For innerLoop = 0 To addRowOffset as well.

Using nested formula in VBA

I'm working on problem that necessitates the use of nested formulas in excel. For eg:
I have a column for errors and one for its analysis
Error Analysis
Enter a valid material number Invalid Material
Eg errors:
Enter a valid material number; The material number 1234 does not
exist.
PO number XYZ does not exist.
VIN number 123 does not exist.
Country of origin AB does not exist.
I have a compendium of such errors and their analyis in the next sheet, and I'm using VLOOKUP in conjuction with FIND to lookup the analysis for the known errors.
=VLOOKUP(LEFT(F2, FIND(" ", F2, FIND(" ", F2) + 1) - 1)&"*", 'Sheet2'!A:B, 2, 0)
What i'm trying to do here is extract the first two words from the error and append a * to it and use it in VLOOKUP.
It would be something like Vlookup "PO number *" in the other sheet and get the analysis for it. Asterisk is because I don 't get the same number daily. And I also know that the extracted first two words of the error will be unique. (I know that error with "Enter a" as the first two words will not appear again).
Now I get errors in the same column so I thought of making a button and writing a code which uses the above formula.
I tried to modify some code off the net, but I'm not getting anywhere with it. I'm totally new to VBA. It'd be great if you can provide a snippet for this. I'll try to replicate the procedure for other needs.
This code seems to be working for now
Sub PopulateAnalysis()
Dim an_row As Long
Dim an_clm As Long
Dim lft As String
Dim st_num As Integer
Dim fin As String
Dim searchStr As String
Dim soughtStr As String
Table1 = Sheet1.Range("F2:F6") 'ErrorColumn from Error table (How do I make the range dynamic??)
Table2 = Sheet5.Range("A1:B6")
an_row = Sheet1.Range("G2").Row ' Populate this column from the analysis table on sheet2
an_clm = Sheet1.Range("G2").Column
For Each cl In Table1
'How do I translate the above formula into VBA statements??
st_num = InStr(InStr(cl, " ") + 1, cl, " ")
lft = left(cl, st_num - 1)
fin = lft & "*"
Sheet1.Cells(an_row, an_clm) = Application.WorksheetFunction.VLookup(fin, Table2, 2, True)
an_row = an_row + 1
Next cl
MsgBox "Done"
End Sub
This should work. You don't need the debug lines of course ;)
Sub PopulateAnalysis()
Dim rngTableWithErrors As Range
Dim rngTableWithAnalysis As Range
Application.ScreenUpdating = False
'set the range for Table with error, Table1 on sheet 1
With Sheets(1) 'change to name of the sheet, more reliable than index num.
Set rngTableWithErrors = .Range("F2:F" & .Cells(.Rows.Count, 6).End(xlUp).Row)
Debug.Print rngTableWithErrors.Address
End With
'set the range for Table with Analysis, Table 2 on sheet 2
With Sheets(2) 'change to name of the sheet, more reliable than index num.
Set rngTableWithAnalysis = .Range("A1:B" & .Cells(.Rows.Count, 2).End(xlUp).Row)
Debug.Print rngTableWithAnalysis.Address
End With
'formula for cell G2
'=VLOOKUP(LEFT(F2;FIND(" ";F2;FIND(" ";F2)+1)- 1)&"*";Sheet2!A1:B23;2; 0)
rngTableWithErrors.Offset(0, 1).FormulaR1C1 = _
"=VLOOKUP(LEFT(R[0]C[-1],FIND("" "",R[0]C[-1],FIND("" "",R[0]C[-1])+1)-1)& ""*"",Sheet2!R1C1:R" & rngTableWithAnalysis.Rows.Count & "C2,2, 0)"
Application.ScreenUpdating = True
MsgBox "Done"
End Sub
Notes
You can notice, that we are setting the upper left cells of ranges manually. It's better practice to somehow find the upper left cells (using Find method is my favorite) and work from there. You never know, how the user will change the worksheet - i.e. add new rows, columns etc.

Excel VBA - Loop through range and set formula in each cell

I've got a workbook where I have one worksheet which contains a lot of data.
My goal is to create a macro that inserts a formula in a separate sheet to copy the data from the first sheet. Lets call the first sheet "Numbers1" and the second sheet "TidyNumbers1".
In the sheet "TidyNumbers1" I want to loop through each cell from column A to M and rows 1 to 60. So I've got a macro that so far looks like this:
Sub updateFormulasForNamedRange()
Dim row, col, fieldCount As Integer
colCount = 13
RowCount = 60
For col = 1 To colCount
For row = 1 To RowCount
Dim strColCharacter
If col > 26 Then
strColCharacter = Chr(Int((row - 1) / 26) + 64) & Chr(((row - 1) Mod 26) + 65)
Else
strColCharacter = Chr(row + 64)
End If
Worksheets("TidyNumbers1").Cells(row, col).Formula = "=IF(Numbers1!E" & col & "<>0;Numbers1!" & strColCharacter & row & ";"")"
Next row
Next col
End Sub
But the formula is supposed to looks like this for Column A, row 2:
IF(Numbers1!E2<>0;Numbers1!A2;"")"
And the formula in Column A, row 3 should look like this:
IF(Numbers1!E3<>0;Numbers1!A3;"")"
Formula in Column B, row 2 should look like this:
IF(Numbers1!E2<>0;Numbers1!B2;"")"
In other words, the formula looks to see if the value in Column E, row % is anything but 0 and copies it if conditions are met.
But, I see that I need to translate my integer variable Row with letters, because the formula probably needs "A" instead of 1. Also, I get a 1004 error (Application-defined or object-defined error) if I just try to use:
Worksheets("Numbers1").Cells(row, col).Formula = "=IF(Numbers1!E" & row & "<>0;Numbers1!" & col & row & ";"")"
I clearly see that the integer row should be translated to letters, if that's possible. Or if anyone has any other suggestions that might work. Also, the 1004 error is unclear to me why happens. I can define a string variable and set the exact same value to it, and there's no error. So it's probably the formula bar that whines about it I guess?
Here is a former post of mine containing functions for conversion of column numbers to letters and vice versa:
VBA Finding the next column based on an input value
EDIT: to your 1004 error: Try something like this:
=IF(Numbers1!E" & row & "<>0,Numbers1!A" & row & ","""")"
(use ; instead of ,, and "" for one quotation mark in a basic string, """" for two quotation marks).
Would not it be easier to get the cell address with the Cells.Address function?
For example:
MsgBox Cells(1, 5).Address
Shows "$E$1"
Best Regards

Resources