Inserting Excel formula that refers to alternative columns - excel

I am trying to insert the following formula ='External Costs B0'!F73 in the same row of a sheet in consecutive columns, however with the cell reference "F73" in worksheet "External Costs" referring to alternate columns e.g F73, H73, J73, L73 etc.
Here is a screen shot of the spreadsheet with formula commented
Screen Capture of formula sheet
This is the code I have tried but I am struggling to figure how to get the alternative column reference working.
Dim CostColumns As Long
'Select cell to start inserting the formula from
Range("E26").Select
'Start from column F (6) in the "External Costs B0" sheet and step to every alternate column
For CostColumns = 6 To 600 Step 2
ActiveCell.Formula = "= ""'External Costs B0'!"" & Rows(73)Columns(CostColumns)"
Move to the next cell to insert the formula in and advance the column reference by 2 columns
ActiveCell.Offset(0, 1).Select
Next CostColumns
The net result is the same error I have seen in many posts:
Application-defined or object-defined error.
Here are many other syntax's for the formula insert I have tried with no success. Any help is greatly appreciated. The below refers to row 40 instead of row 73 in the External Costs B0 sheet as per the example above.
Range("E26").Select
For CostColumns = 6 To 66 Step 2
'ActiveCell.FormulaR1C1 = "= worksheets("""External Costs B0""").Cells(40,6).Value"
'ActiveCell.FormulaR1C1 = "='External Costs B0'!R[14]C[CostColumns]"
'Range("E26:AK26").FormulaR1C1 = "='External Costs B0'!R[14]C[CostColumns]"
'ActiveCell.FormulaR1C1 = "= worksheets('External Costs B0')!" & " Rows(40)Columns(CostColumns)"
'Range("E26:AK26").FormulaR1C1 = "='External Costs B0'!R[14]C[+2]"
'Range("E26:AK26").FormulaR1C1 = "=Wksht.Cells(40,CostColumns) &"
'Range("E26:AK26").Formula = "=worksheets('External Costs B0'!)" & ".Cells(40,6)"
'ActiveCell.Formula = "= worksheets('External Costs B0'!).Cells(40,6).Value"
ActiveCell.Offset(0, 1).Select
Next CostColumns

Use this:
ActiveCell.Formula = "='External Costs B0'!" & Cells(73, CostColumns).Address(0, 0)
The problem with that is that Rows(73) and Columns(CostColumns) both return a Range object which you can't concatenate to a string.

Its way easier, if you use FormulaR1C1 and no selects like in the following sub:
(please change R, RowOffset and FormulaUntilColumn to your needs)
Sub Formulas()
Dim I As Integer
Const R As Long = 9 'row
Const RowOffset As Integer = -8
Const ForumulaUntilColumn As Long = 7
For I = 1 To ForumulaUntilColumn
Cells(R, I).FormulaR1C1 = "=R[" & RowOffset & "]C[" & I - 1 & "]"
Next I
End Sub
P.S.: add workbook and table name as in any other formula between '=' and 'R['

This code will place your formula in cells Sheet1!A1:AD1.
The formula in A1 will be ='External Costs B0'!$A$73.
In B1 it will be ='External Costs B0'!$C$73 and so on up to ='External Costs B0'!$BG$73 in cell AD1.
Sub PasteFormula()
Dim CostColumns As Long
Dim y As Long
'Starting column for External Costs reference
CostColumns = 1
With ThisWorkbook.Worksheets("Sheet1")
For y = 1 To 30
.Cells(1, y).FormulaR1C1 = "='External Costs B0'!R73C" & CostColumns
CostColumns = CostColumns + 2
Next y
End With
End Sub
To update the code change Sheet1 to whichever sheet you need to
formula to appear in.
Change CostColumn=1 to the correct column
number you want the formula to refer to.
Change y = 1 To 30 to
the correct columns you want the formula to appear in.
The code uses R1C1 syntax as it's easier to update a formula if you only need to deal with row & column numbers R73C2 is row 73, column 2 for example.

Related

Dynamic Column Index Name Error in Formula

I am trying to calculate the component q'ty from Sheet Plan to Sheet Result by using Vlookup to fill in column,having:
Count_col: is the total column in sheet Plan
Last_col: is the total column in sheet Result (before add column Demand)
Sheet Results
Material
Component
Demand W1
Demand W2
ABCD1000
nc200
#NAME?
#NAME?
Sheet Plan
Material
Demand W1
Demand W2
ABCD1000
1000
200
For i = 1 To count_col
Cells(1, i + last_col).Value = "=Plan!RC[-2]"
Cells(1, i + last_col).Offset(1, 0).Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC1,Plan!C1:C15,i+1,0)"
Next i
But the result is name error, I checked the spelling of function is correct and dont know how to fix. Why there is "#" in my formula?
Detail of error
=VLOOKUP($A2,Plan!$A:$O,#i+1,0)
i+1 inside "" behaves like a string rather than a variable. Try this.
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC1,Plan!C1:C15," & i + 1 & ",0)"
Also avoid the use of .Select. Your code can be written as
Cells(1, i + last_col).Offset(1, 0).FormulaR1C1 = _
"=VLOOKUP(RC1,Plan!C1:C15," & i + 1 & ",0)"
Recommended Reading: How to avoid using Select in Excel VBA
Also you are mixing R1C1 and A1 style of referencing. I would recommend using one of them. A simple Google search R1C1 vs A1 style will explain what they are.
In R1C1, Plan!C1:C15 needs to be written as Plan!R1C3:R15C3. So your final code would be
Cells(1, i + last_col).Offset(1, 0).FormulaR1C1 = _
"=VLOOKUP(RC1,Plan!R1C3:R15C3," & i + 1 & ",0)"

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 Sum from Multiple Sheets

I am trying to create a function or functions that can sum daily hours from time cards for each client to come up with the total hours worked per day. Each client has it's own sheet inside of a single workbook.
Currently, I have a function that determines the sheet that goes with the first client (the third sheet in the workbook):
Function FirstSheet()
Application.Volatile
FirstSheet = Sheets(3).Name
End Function
And one to find the last sheet:
Function LastSheet()
Application.Volatile
LastSheet = Sheets(Sheets.Count).Name
End Function
The part that I am having trouble with it getting these to work within the sum function.
=sum(FirstSheet():LastSheet()!A1
That is basically what I want to accomplish. I think the problem is that I don't know how to concatenate it without turning it into a string and it doesn't realize that it is sheet and cell references.
Any help would be greatly appreciated.
So, an example formula would look like this:
=SUM(Sheet2!A1:A5,Sheet3!A1:A5,Sheet4!A1:A5)
That would sum Sheet2-Sheet4, A1:A5 on all sheets.
Is there a reason you need to write the VBA code to do this?
Can't you just enter it as a formula once?
Also, if you're going to the trouble of writing VBA to generate a formula, it may make more sense to just do the sum entirely in VBA code.
If not, try this:
Sub GenerateTheFormula()
Dim x, Formula
Formula = "=SUM(" 'Formula begins with =SUM(
For x = 3 To Sheets.Count
Formula = Formula & Sheets(x).Name & "!A1," 'Add SheetName and Cell and Comma
Next x
Formula = Left(Formula, Len(Formula) - 1) & ")" 'Remove trailing comma and add parenthesis
Range("B1").Formula = Formula 'Where do you want to put this formula?
End Sub
Results:
The functions return strings and not actual worksheets. The Worksheet does not parse strings well. So add a third function that uses the Evaluate function:
Function MySum(rng As Range)
MySum = Application.Caller.Parent.Evaluate("SUM(" & FirstSheet & ":" & LastSheet & "!" & rng.Address & ")")
End Function
Then you would simply call it: MySum(A1)
It uses the other two function you already have created to create a string that can be evaluated as a formula.
I didn't understand ur question completely but As I understood u have different sheets of different clients which contains supoose column 1 date and column 2
contains hours on that particular date wise hours and a final sheet which column1 contains name of client and column 2 contains total hoursPlease try it
Sub countHours()
Dim last_Row As Integer
Dim sum As Double
sum = 0
'Because I know number of client
For i = 1 To 2 'i shows client particular sheet
last_Row = Range("A" & Rows.Count).End(xlUp).Row
Sheets(i).Activate
For j = 2 To last_Row
'In my Excel sheet column 1 contains dates and column 2 contains number of hours
sum = sum + Cells(j, 2)
'MsgBox sum
Next j
'Sheet 3 is my final sheet
ThisWorkbook.Sheets(3).Cells(i + 1, 2).Value = sum
sum = 0
Next i
End Sub
Happy Coding :

VBA clean up conditional duplication of rows

I have a data set in which there is an id field and a number of other fields.
The id field at times has a second id. In this case, I need to create a new duplicated record and put a single id in each of the records. There is an additional condition in which each of the ids may be followed by a number which is a percentage. In all cases, I need to display the correct percentage as a decimal value in a field on the record.
id examples:
AJ01-25/ST01-75
AJ01/LM03
RICH01
Correct representation of ids and percentages:
id percent
AJ01 .25
ST01 .75
AJ01 .5
LM03 .5
RICH01 1.0
I used the following code to create a new record and parse any percentages into a new field whenever a "/" is detected, but I'd very much like to have something cleaner. Sort order does not matter (my script places new records at the end). Thoughts?
Sub breakemup()
Dim wb As Workbook
Dim ws As Worksheet
Dim id As String
Dim rng As Range
Dim ar() As String
Set wb = ThisWorkbook
Set ws = wb.Worksheets("data")
Dim currentRow As Integer
Dim finalRow As Integer
finalRow = ws.UsedRange.Rows.Count
For currentRow = 2 To finalRow
ar() = Split(ws.Range("a" & currentRow).Value, "/")
If UBound(ar) = 1 Then
ws.Rows(currentRow).Copy Destination:=ws.Range("A" & Rows.Count).End(xlUp).Offset(1)
If UBound(Split(ar(1), "-")) = 1 Then
ws.Range("A" & Rows.Count).End(xlUp).Value = Split(ar(1), "-")(0)
ws.Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = CDbl(Split(ar(1), "-")(1)) / 100#
ws.Range("A" & currentRow).Value = Split(ar(0), "-")(0)
ws.Range("A" & currentRow).Offset(0, 1).Value = CDbl(Split(ar(0), "-")(1)) / 100#
Else
ws.Range("A" & Rows.Count).End(xlUp).Value = ar(1)
ws.Range("A" & Rows.Count).End(xlUp).Offset(0, 1).Value = 50 / 100#
ws.Range("A" & currentRow).Value = ar(0)
ws.Range("A" & currentRow).Offset(0, 1).Value = 50 / 100#
End If
Else
ws.Range("A" & currentRow).Offset(0, 1).Value = 1#
End If
Next
End Sub
Not sure if you would consider this cleaner but here is a formula solution rather than a VBA one. It uses the functions:
INDIRECT
MID
LEN
IF
RIGHT
FIND
Lets say we have the following in sheet 1:
Insert the following formulas in sheet 2:
Cell A2:
=IF(E2=1, IF(D2="", IF(C2="", INDIRECT(G2), LEFT(INDIRECT(G2), C2-1)), LEFT(INDIRECT(G2), D2-1)), IF(D2="",IF(C1="", INDIRECT(G2), RIGHT(INDIRECT(G2), LEN(INDIRECT(G2))-C1)), MID(INDIRECT(G2), C1+1, D2 -1-C1)))
Drag / Copy it down to cover the rest of the cells in column A
Cell B2:
=IF(E2=1,IF(C2="",IF(D2="",1,MID(INDIRECT(G2),C2+1,LEN(INDIRECT(G2)))),IF(D2="",0.5,MID(INDIRECT(G2),D2+1,C2-D2-1)/100)), IF(D2="",0.5,MID(INDIRECT(G2),D2+1, LEN(INDIRECT(G2))-D2)/100))
Drag / Copy it down to cover the rest of the cells in column B
Cell C2:
=IF(E2=1, IF(ISNUMBER(FIND("/",INDIRECT(G2))),FIND("/", INDIRECT(G2)), ""), "")
Drag / Copy it down to cover the rest of the cells in column C
Cell D2:
=IF(E2=1, IF(ISNUMBER(FIND("-", INDIRECT(G2))),FIND("-", INDIRECT(G2)), ""),IF(D1 ="", "", FIND("-", INDIRECT(G2), D1+1)))
Drag / Copy it down to cover the rest of the cells in column D
Cell E2:
The number value "1"
Cell E3:
=IF(E2=1, IF(C2="", 1, 2),1)
Drag / Copy it down to cover the rest of the cells in column E
Cell F2:
the number value "1"
Cell F3:
=IF(E3=1, F2+1, F2)
Drag / Copy it down to cover the rest of the cells in column F
Cell G2:
="Sheet1!A" & TEXT(F2, 0)
Drag / Copy it down to cover the rest of the cells in column G
Result:
You could hide the extra columns so you only see the columns you need:
I have an article on my blog that provides an example with pretty much the same functions used here, it might help with understanding the functions used Excel Functions and Formulas Sample #1, Split Strings Based on Delimeter

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