VBA Function. Running Cumulative Costs across multiple sheets - vba

Long time, first time.
I am creating a sheet for workover rigs in Oil and Gas field work. Each sheet is identical in structure but represents a different day of work. I have buttons that add and subtract sheets as new days are required, which complicates my main problem:
I need to create a function that calculates the cumulative cost of various categories up to that sheet in the workbook. I need a way to reference the cell adjacent to the cell containing the function (containing the current day's cost), as well as the previous sheet's cumulative cost (or each previous sheet's daily cost, in the same cell one sheet back) to create a new cumulative value. I want each sheet's cumulative to be cumulative up to that day.
A subroutine would be much more conducive to this, but I do not want someone to have to click a button to generate a cumulative in these cells. It needs to automatically calculate as information is added.
What I have so far is below. The sheets are named by the numbered day on the job (1,2,3,4 etc) and Cell AD7 in each sheet contains the value of the current day on the job as well. Basically what I need is a way to extract and use the address of the input cell "daily".
Function Cat_Cum(daily)
Dim day, i As Integer
day = Cells(7, 30)
For i = 1 To day
If i = 1 Then
Cat_Cum = Sheets(i).Cells(daily.Address)
Else
Cat_Cum = Sheets(i).Cells(daily.Address) + Cat_Cum
End If
Next i
End Function
Recap worksheet structure:
2 columns: daily cost, cumulative cost.
Each sheet is identical in structure.
Cumulative should be the total of each previous sheet's daily value in that same cell.
Thanks for the help!

IIUC you want your UDF to be like this:
Public Function Cat_Cum(daily As Range)
Cat_Cum = daily.Value2
If Application.caller.Parent.Name = "1" Then Exit Function
Cat_Cum = Cat_Cum + _
Worksheets(CStr(Application.caller.Parent.Name - 1)).Range(Application.caller.Address).Value2
End Function
so in each worksheet named "1", "2", "3" etc.., in the cumulative column you type, =Cat_Cum(A2) in row 2 and fill down. Replace the column of the daily stuff in place of A if it is another column.

Related

Sumif across multiple sheets, specific rows and columns

I have 20 sheets (let's say three, for simplicity) and I need to sumif each of those sheets against one main tab with all the data in it. Each sheet is for a different business entity but each sheet has the same format:
Format: Business 1000
Format: Business 2000
I will insert monthly data into the DATA tab and will need a macro to go into Sheet 1, 2, 3 etc. and run a sumif against the DATA tab matching column B (business unit code). I will also have this run for each month so Row3 will have Actual or Forecast.
The problem:
DATA tab gets deleted and reset with next month's data, therefore all sumifs must change into values.
not all rows are equal, some may have 5-6 items and then a Sum for the total, eg: travel may include hotel, parking, meals, car rental. So SumIF can only run where column B has a code. Otherwise do NOTHING.
I don't know how to code a relative reference inside sumif. I can VBA code a column and tell it to enter "Text" into each non-blank cell. Although I can't tell it to change or have relative cell data.
Then for next month (when data tab gets reset) the next column must be filled in. If it's simpler I can add another row with an X in the active month's column, so the macro can check if there is an X in that row, then do the sum if for that column.
It's simple to run a sum if, copy paste to all non blank rows, and then recopy as value only. But not when I have 20+ sheets, and need to do that every month.
Ok, so here is an example of what you want to do. In this example, I have left it up to you to set in the code which column you are looking to fill this month.
Change the value of Const ColumnNumber = 4 to change the column you are filling this month 4=D, 5=E etc (Apologies I only work in R1C1 ref style).
FirstRow always appears to be 4, but I have left that there in case you need to change it.
Worksheetfunction.sumif takes parameters in the same order as the normal sumif, so I am passing in column 1 of the data sheet for the range, cell c of the same row as the criteria, and column 2 of the data sheet as the sum range.
Using worksheetfunction.sumif will return the value to the cell, not the formula so that solves your problem of the data sheet being deleted and recreated.
I have also left the option for you to fill in the green rows with something else.
Const ColumnNumber = 4
Const FirstRow = 4
Sub LoopSomeSheets()
Dim sht As Worksheet
'go through each sheet in the workbook
For Each sht In ThisWorkbook.Sheets
'ignore the sheet named "data"
If sht.Name <> "data" Then
Dim LastRow As Long
'figure out where the sheet ends
LastRow = sht.cells.SpecialCells(xlCellTypeLastCell).Row
'variable to sum totals
Dim RunningTotal as Double
For i = FirstRow To LastRow
If sht.Cells(i, 3).value = "SUM" Then
'Put the total value in the sum cell
sht.Cells(i, ColumnNumber).value = RunningTotal
'reset the total for the next group
RunningTotal = 0
Else
Dim SumOfData as Double
'get the sumif value
SumOfData = _
WorksheetFunction.SumIf(Sheets("data").Columns(1), sht.Cells(i, 2), Sheets("data").Columns(2))
'add to the running total
RunningTotal = RunningTotal + SumOfData
'then update the cell
sht.Cells(i, ColumnNumber).value = SumOfData
End If
Next i
End If
Next sht
End Sub

Translating results by day to results by week with excel vba

In my excel sheet I have an varying number of dates in column A with associated totals for each date in column B. The dates are somewhat random but I want to find the sum of the associated totals per week. I'm new to vba and I'm having a bit of trouble figuring out how to calculate the totals per week.
The psudo code for what I'm thinking is:
buttonClicked()
Dim sum As Integer, tempDate As Date, current As Date, i As Integer, j As Integer, match As Boolean
sum = 0
tempDate = Range("A1").Value
current = tempDate
For i = 1 To Rows.Count
for j = 0 to 7
tempDate = addDate(d, i, tempDate)
If cell(i,1).Value = tempDate Then sum = sum + cell(i, 2).Value
match = true
Break
End If
Next j
If match = true Then tempDate = current
Else
`next open space in column D is current
current = tempDate
`next open space in column E is sum
sum = 0
Next i
end
Please let me know if there's any better way to solve this problem other than iterating through the entire list and counting 7 days ahead. I should note that A1 is already assumed to be a sunday and I'm not sure how the commented out lines should be implemented. I would be very grateful for any advice at all.
In other column assign the corresponding Year.WeekNumber to each row using the following formula:
=CONCATENATE(YEAR(A1),".",TEXT(WEEKNUM(A1),"00"))
The totals per Year.Week can be obtained using a SUMIF formula or via a PivotTable. The PivotTable can be auto resize if you use a Dynamic Range as DataSource
If you are looking for a series of 7 row sums from column B, then this formula using native worksheet functions should do.
=SUM(INDEX(B:B, (ROW(1:1)-1)*7+1):INDEX(B:B, (ROW(1:1)-1)*7+7))
Fill down to catch successive week periods.
      
If you can supply a starting date (e.g. =MIN(A:A)) and add 7 to it in successive rows, then the weekly starting date could be a reference point for a SUMIFS function. In E9 as,
=SUMIFS(B:B,A:A, ">="&D9,A:A, "<"&D9+7)
Fill down as necessary.
If a VBA solution is necessary, that logic can be brought into a VBA sub or function.

Excel Formula to calculate number of user hits in a system everyday

This is the continuation of my previous questions and I have included my global aim with project.
Excel Link:
https://drive.google.com/file/d/0B5W4CgZKsARFSmhqV0ZSM1lBSkE/view?usp=sharing
Task:
The task is to collect the "number hits" of a user in an application "on each day". I can collect a log from the system which will give me the name of the users and their last hit date and total number of hits.(This total number of hits in not on daily basis, but sum of all days). and I need to make a formula to segregate these on daily basis
Screenshot:
To understand in better way I have created few screenshot, which I am looking to implement.
The excel has two tabs raw_data and value_capture. I will use raw_data to paste my raw data collecting from system log and value_capture to generate day by day hit statistics
Raw_data tab:
It has three details, 1. date. 2. name and 3 totals hits(This total hits are overall hits of that user on all days)
value_capture:
This has all user names and all dates to mark each day and a column to display all hits.
Now, considering an example of date 20141120, all users hits are 0.
raw_data shows 0 against all users
so value_capture are has to be updated with same
Now on next day 20141121, there is some hits against some users. (Note : if there is no hit against a user, it will only the previous date ie,date will update only if there is a hit on that day)
value_capture updated with that details
On 20141122, there are some more hits against the users
value_capture updated with the details. since the raw_data will show total number of hits against a user, the way of calculating on a particular will be total hits- previous date hit
I am stuck at a way to develop the excel formula here.Looking for an idea to implement this.
Note :
Users name will be fixed on both tabs, but that may come in different order in raw_data tab.
UPDATE
My raw_data sheet will be updated everyday and I want my formula results be fixed in the value_capture sheet after the values are updated (removed) from sheet raw_data
So as i mentioned in my answer to your previous question, the only way to save the results of a formula after deleting/removing its reference cells, is to use a macro.
First of all
you need a proper formula to pull the data from the raw_data sheet and then calculate the difference between that particular cell where the formula resides and the sum of previous cells in that row.
we need two formulas:one for the column B of your value_capture sheet. and the second one for the rest of your table. why? because in the first column you don't calculate the difference between itself and the previous cells, because there aren't any. So there is a little difference in the formula.
FORMULA ONE:(paste in B3 and drag and fill down)
=SUMIFS(raw_data!$C:$C;raw_data!$B:$B;$A3;raw_data!$A:$A;B$2)
FORMULA TWO:(paste in C3 and drag and fill down and to the right)
=IF(SUMIFS(raw_data!$C:$C;raw_data!$B:$B;$A3;raw_data!$A:$A;C$2)-IF(ISNUMBER(B3);SUM($B3:B3);0)>0;SUMIFS(raw_data!$C:$C;raw_data!$B:$B;$A3;raw_data!$A:$A;C$2)-IF(ISNUMBER(B3);SUM($B3:B3);0);0)
As you see in my screenshot for user in cell A3, we have value of 4 for the date 20141120 and the next day the value is 14 but the cell gets the difference, that is 10, and then then next day, the value increases to 16, so the cell value for D3 becomes 2 which is the different of 16 for that day and the sum of previous ones. This continues until today's value which is 24 so the cell gets 7 because the sum of previous ones is 17.
Now that you have your values captured correctly, with respect to the difference with the sum of previous days, it is time to make them fixed and eternal.
For this you need a macro:
Sub saveMyData()
Dim ws As Worksheet
Set ws = ActiveSheet
ws.Range("B3:L18").Copy
ws.Range("B3").PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
End Sub
So obviously you need to update this range "B3:L18" this is what I have in the example sheet only.
Now this macro, copies and pastes all the values from that range onto itself, so you lose your formulas.So each day, you need to go to *line 21** of the same sheet and get the formula from C21 and paste it on somewhere on row 3 from where you want to continue capturing the new day's data. (you won't need the first formula, because it is only used once in the first column, the first day.)
This was the only way to capture the values using formulas and then save the results of the formulas in their place and go and fetch new data. I couldn't think of any other strategy to make it more automatic, except for writing mova VBA and letting excel go and find where you left the day before and paste the formulas in their right place and repeat the task.
all these formulas are array formulas, so press ctrl+shift+enter to calculate the formulas.
Remember to adjust the formulas to your regional settings, i suppose, by replacing the ";" with ",".
here is the example sheet downloadable from this link
Tell me if you have problems anywhere and don't forget to answer my question in the comments about the way you update your dates in row 2 of value_capture.
The formula that you are looking for is SUMIFS
=SUMIFS([SUM RANGE],[RANGE 1],[VALUE 1],[RANGE 2],[VALUE 2])
SUM RANGE is the column of values that you want to SUM so that is your column C. For Range 1 you want to select the range of IDs. The VALUE 1 will be equal to the value in Column A Row X. For RANGE 2 it will be the Date column. For VALUE 2 it will be the value in the column header.
Put this together and you have something akin to:
=SUMIFS(raw_data!$C:$C,raw_data!$B:$B,$A3,raw_data!$A:$A,B$2)
This would be in cell B3 and you could fill the other cells from there.
If total hits for a day is a rolling count of ALL hits ever then at the end of your equation you need to subtract the sum of the prior days.
For example:
=SUM(B3:B4)
This would only need to be added to subsequent columns (not the first).
So the equation in C3 would be
=SUMIFS(raw_data!$C:$C,raw_data!$B:$B,$A3,raw_data!$A:$A,C$2)-SUM(B$3:C3)
Then in D3 it becomes
=SUMIFS(raw_data!$C:$C,raw_data!$B:$B,$A3,raw_data!$A:$A,D$2)-SUM(B$3:D3)
Try Sumifs formula
=SUMIFS(raw_data!$C:$C,raw_data!$B:$B,$A3,raw_data!$A:$A,B$2)-IF(ISNUMBER(A3),A3,0)

VBA Excel - Summing a range of cells based on result in a different range of cells

I am attempting create a forecasting function in excel using based on a set of preregistered historical data. I am new to VBA and I am unable to make this function.
I have three Ranges:
Range 1 lists every day in a year. All cells are formatted in the form of "date".
Range 2 on a different sheet named "C" also lists every day in a year. All cells are formatted in the form of "date".
Range 3 on sheet "C" contains the dollar value actualized in the specific date of the year mentioned in Range 2.
Requirement:
The function should take 3 different variables which are the three different ranges. The Function should first "LOOKUP" the month and year of the selected cell and match it with the month of and (year -1) of the cells in Range two.
Accordingly, The cells in Range 3 on the same row in which the "LOOKUP" matches with Range 2 should sum up and then divide by the count of cells counted.
So far I have been able to create a function named MNAME.
Function MNAME(x As Variant) As String
Dim CurrentMonth As Date
CurrentMonth = x
MNAME = MonthName(Month(CurrentMonth), True)
End Function
But I am failing to nest the lookups and sum up the values.
you dont need VBA.
Read Up on the SUMPRODUCT() function - Here is a good explanation
to summarise your problem you want to find out:
if the year of the cells in Range2 is the same as YEAR(reference_cell)-1
--> IF(YEAR(reference_cell)-1=YEAR(Range2))
if the month of the cells in Range2 is the same as MONTH(reference_cell)
--> IF(MONTH(reference_cell)=MONTH(Range2))
where 1. IS TRUE and 2. IS TRUE, sum corresponding cells in Range3
--> =SUMPRODUCT(--(YEAR(reference_cell)-1=YEAR(Range2))*--(MONTH(reference_cell)=MONTH(Range2))*Range3)

PivotCache Refresh - Cell formula return #Value

I have a pivot table created from external data source(access) that contain number of records for each hour on a weekly basis for an average period of 3 months. Just beside this pivot table, I've created a column that calculates the average number record for each hour for a day. (A week here is just 5 days - sat & sun don't count).
To achieve the above, I have created a UDF that counts the number of weeks from the pivot data field (Week_Ending). To ensure the code don't count ghost or non-existent weeks, I have used the pivotcache refresh in the UDF. This works perfectly, except it now gives #value (A value used in the formula is the wrong data type) in the cells where I expect the daily average. I have found no issue with the cell formula and works if a single week is selected from the field "Week_Ending" instead of ALL.
I have attached the code and cell function and an image of the issue.
Cells formula in Cell E6 and it is similar upto cell E29 (Hourly cell reference is incremented by 1 for each cell)
=IF($E$4=1,GETPIVOTDATA("CountOfCase_Id",$A$4,"HOURLY",A6)/5,GETPIVOTDATA("CountOfCase_Id",$A$4,"HOURLY",A6)/($E$4*5))
Vba UDF function
Option Explicit
Function WeekCount(InputVal As Variant) As Integer
Dim book1 As String, PivotName As String
book1 = ThisWorkbook.Name
With Workbooks(book1).ActiveSheet
If InputVal = "(All)" Then
PivotName = .PivotTables(1).Name
.PivotTables(PivotName).PivotCache.MissingItemsLimit = xlMissingItemsNone
.PivotTables(PivotName).PivotCache.Refresh
WeekCount = .PivotTables(PivotName).PivotFields("WEEK_ENDING").PivotItems.Count
Else
WeekCount = 1
End If
End With
End Function
I appreciate any help. Excel version is 2003.
The problem turned out to be with
.PivotTables(PivotName).PivotCache.Refresh
in the UDF and not fixed with Application.Volatile. However #GSerg’s solution without p.update seems to have worked.