Excel VBA Sum from Multiple Sheets - excel

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 :

Related

Excel VBA Sum up/Add values together, even those with commas/decimal

I have a problem where I can't add numbers with decimals. Only numbers with no decimals.
I have written a code to sum up values from different cells. This work fine as long as the numbers are without decimals.
Here is my code:
Sub SumValues()
'This makro is made to add values together depending on
'x amount of Sheets in the workbook:
Application.ScreenUpdating = False
'A will sum up the values from each cell,
'depending on the amount of Sheets in the this Workbook:
A = 0
For I = 1 To ThisWorkbook.Sheets.Count
'Adding the values from cell E5 to Cells(5, 5 + (I - 1) * 3),
'with the distance 3 between each cell:
A = A + Cells(5, 5 + (I - 1) * 3)
Next I
'The values A that is added togheter from the cells, is now put in a cell:
Worksheets("Sheet1").Cells(1, 1).Formula = "=" & A & ""
Application.ScreenUpdating = True
End Sub
So for 3 number of sheets, "I" goes from 1 to 3.
So if my cells contain these numbers:
Cell(5,5) = 2
Cell(5,8) = 3
Cell(5,11) = 8
I get the sum in Cell(1,1) = 13
But if I have these values:
Cell(5,5) = 2,2
Cell(5,8) = 3
Cell(5,11) = 8
I get the "run-time error '9': Subscript out of range" Error message when running script.
Any suggestions?
Another question is if it is possible to get the formula into the cell I am adding up the values?
For Examlpe if I have 3 Sheets in my Workbook, it will sum up the values from Cell(5,5) , Cell(5,8) and Cell(5,11).
The sum is shown in Cell(1,1).
But all I get is the number, not the formula.
Is it possible to make the Cell show the formula "=E5+H5+K5"?
This last question might be a "fix" for the first question, if it is the separator "," that is making trouble, maybe?
Thanks
GingerBoy
Tested and working fine
Declare your variables
You need to qualify your objects with a worksheet
No need to toggle off Screen Updating here. You are just modifying one cell
This code will place the Value in A1 and the Formula in B1
Disclaimer:
Your code, and the code below, is subject to a potential Type Mismatch Error if you feed any cell with a non-numerical value into your loop. If there is some chance of any non-numerical cell being in the sum range, you can avoid the error by nesting something like the following inside your loop: If ISNUMERIC(Range) Then.
Sub SumValues()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim A As Double, i As Long, Loc As String
For i = 1 To ThisWorkbook.Sheets.Count
A = A + ws.Cells(5, (5 + (i - 1) * 3))
Loc = ws.Cells(5, (5 + (i - 1) * 3)).Address(False, False) & "+" & Loc
Next i
ws.Range("A1") = A
ws.Range("B1").Formula = "=" & Mid(Loc, 1, Len(Loc) - 1)
End Sub

Inserting Excel formula that refers to alternative columns

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.

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 Macro - pull cell function until the end of the table

I will use an example to illustrate my question:
I have many tables which their lines quantity is different.
I want to pull down the function until the end of the table.
For example:
A B
1 =1*2 // <- this is the function that I want to pull
2
3
4
The output should be:
A B
1 =1*2
2 =2*2
3 =3*2
4 =4*2
It is important that the pull length is determined by the last cell at column A (in this case it is 4)
Please also note that the function may be changed either, this should work for any function.
Thank you,
Doron
Here is an example of a macro that will autofill the value from cell B1 to the end of the column to the left of it (in this case column A).
Sub AutoFill()
Dim FillFrom As Range
Set FillFrom = ActiveSheet.Range("B1")
FillFrom.AutoFill Destination:=Range(FillFrom.Address, FillFrom.Offset(0, -1).End(xlDown).Offset(0, 1).Address)
End Sub
Try This:
Public Sub DoWhatIWantYouToDo()
Dim lr As Integer, i As Integer
lr = Sheets("Sheet1").UsedRange.Rows.Count
For i = 2 To lr
Sheets("Sheet1").Range("B" & i).Formula = "=" & " A" & i & "*2"
Next
End Sub

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