Sum up data per row based on dates - excel

I've got some data as seen below from row 2-7.
I would like to combine all the data from previous months into one row, so from the picture below, I would like to combine the data from 05/05/2014-07/09/2014, but leave the most recent month 's data untouched and not combined. So I need to sum up the data in column G and column H, for rows 2-4, the other columns don't matter.
Rows 11-14 is what I would like to achieve. How would I do that (macro or otherwise)?

See if this will get you started:
Sub Summary()
Dim FirstDataRow As Long
Dim LastDataRow As Long
Dim DataRow As Long
Dim cDates As Long
Dim cAmounts As Long
Dim CutoffDate As Date
Dim EarliestOldDate As Date
Dim LatestOldDate As Date
Dim SumOfOld As Long
Dim OldMonthsRow As Long
Dim OffSetToSummaryTable As Long
Dim InputRow As Long
Dim OutputRow As Long
Dim TheDate As Date
Dim TheAmount As Long
Dim ws As Worksheet
' INITIALIZE
' Assume we're operating on the activesheet
Set ws = ActiveSheet
' Assume data starts in Row 2
FirstDataRow = 2
' Assume data is a contiguous block
LastDataRow = ws.Range("F" & CStr(FirstDataRow)).End(xlDown).Row
' Assume 3 empty rows between input and summary table
OffSetToSummaryTable = 3
' Calculate row where sum of old months goes
OldMonthsRow = LastDataRow + OffSetToSummaryTable + 1
' Calculate the cutoff date = first date of current month
CutoffDate = DateSerial(2015, 1, 1)
' CutoffDate = DateSerial(Year(Date), Month(Date), 1)
' Column where dates are
cDates = 6
' Column where amounts are
cAmounts = 7
' Initialize earliest and latest old dates, and sum of old
EarliestOldDate = DateSerial(3000, 12, 31) ' Way out in the future
LatestOldDate = DateSerial(1904, 1, 1) ' Way back in the past
SumOfOld = 0
' PROCESS THE DATA
OutputRow = OldMonthsRow
For InputRow = FirstDataRow To LastDataRow
TheDate = ws.Cells(InputRow, cDates)
TheAmount = ws.Cells(InputRow, cAmounts)
If TheDate >= CutoffDate Then
' Add at the bottom of the summary table
OutputRow = OutputRow + 1
ws.Cells(OutputRow, cDates).Formula = TheDate
ws.Cells(OutputRow, cAmounts).Formula = TheAmount
Else
' Update results for previous months
EarliestOldDate = IIf(TheDate < EarliestOldDate, TheDate, EarliestOldDate)
LatestOldDate = IIf(TheDate > LatestOldDate, TheDate, LatestOldDate)
SumOfOld = SumOfOld + TheAmount
End If
Next InputRow
' WRITE RESULTS TO SUMMARY ROW
ws.Cells(OldMonthsRow, cDates).Formula = Format(EarliestOldDate, "dd/mm/yyyy") & " - " & Format(LatestOldDate, "dd/mm/yyyy")
ws.Cells(OldMonthsRow, cAmounts).Formula = SumOfOld
Set ws = Nothing
End Sub

Related

Can I give an if statement by subtracting time?

Is there a way to make my VBA code work for my macro? I want my macro's if function to read the first column of each worksheet in my excel (it has as many sheets as days in the exact month i'm working on), read through each cell and if the currently read cell is equal to or larger than '15 minutes compared to the first cell, then the code would execute, otherwise go to the next cell in the first column.
This is the format of the worksheets i'm working on:
TimeStamp
Power Consumption
Power Production
Inductive Power Consumption
2021.01.01. 8:12:38 +00:00
747
575
3333
2021.01.01. 8:17:35 +00:00
7674
576
3333
... etc ,
And my code looks something like this:
Sub stackoverflow()
Dim w As Integer 'index of worksheets
Dim i As Integer 'row index that steps through the first column
Dim t As Integer 'reference row index i inspect the time to
Dim x As Integer 'row index where i want my data to be printed
Dim j As Integer 'col index
Dim Timediff As Date 'not sure if this is even needed
t = 2
j = 1
x = 1
'Timediff = ("00:15:00")
For w = 3 To ActiveWorkbook.Worksheets.Count 'for every sheet from the 3rd to the last
lRow = ActiveWorkbook.Worksheets(w).Cells(Rows.Count, 1).End(xlUp).Row 'find the last row in each worksheet
lCol = ActiveWorkbook.Worksheets(w).Cells(1, Columns.Count).End(xlToLeft).Column 'find the last column in each worksheet
For x = 2 To lRow
For i = 2 To lRow
'If the time in cell(i,j) is >= then cell(t,j) + 15 minutes,
If Cells(i, j) >= DateAdd("n", 15, Cells(t, j)) Then
ActiveWorkbook.Worksheets(w).Range(i, j).Copy ActiveWorkbook.Worksheets(2).Range(x, j)
ActiveWorkbook.Worksheets(w).Range(i, j + 1).Copy ActiveWorkbook.Worksheets(2).Range(x, j + 1)
'put the new reference point after the found 15 minute mark
t = i + 1
Else
End If
Next i
Next x
Next w
End Sub
So all in all I want my code to notice when the first column reaches a 15 minute mark, and execute some code (subtracting the values of the 15 minute mark from the reference where it started, put the value in the'2nd sheet, and then step to the next cell, and repeat the process).
I'm not entirely sure which information you are attempting to copy to the second worksheet but the following code should be able to get you there pretty easily. Additionally, I've added a function that will fix the format of your TimeStamp field so that excel will recognize it and we can then do math with it
Sub TestA()
Dim xlCellA As Range
Dim xlCellB As Range
Dim xlCellC As Range
Dim i As Integer
Dim j As Integer
Dim lRow As Long
Dim lCol As Long
Set xlCellA = ActiveWorkbook.Worksheets(2).Cells(2, 1)
For i = 3 To ActiveWorkbook.Worksheets.Count
lRow = ActiveWorkbook.Worksheets(i).Cells.SpecialCells(xlCellTypeLastCell).Row
lCol = ActiveWorkbook.Worksheets(i).Cells.SpecialCells(xlCellTypeLastCell).Column
Set xlCellB = ActiveWorkbook.Worksheets(i).Cells(2, 1)
xlCellB.Value = FixFormat(xlCellB.Value)
xlCellB.Offset(0, lCol + 1).Value = "=DATEVALUE(MID(" & xlCellB.Address & ",1,10))+TIMEVALUE(MID(" & xlCellB.Address & ",12,8))"
For j = 3 To lRow
Set xlCellC = ActiveWorkbook.Worksheets(i).Cells(j, 1)
xlCellC.Value = FixFormat(xlCellC.Value)
xlCellC.Offset(0, lCol + 1).Value = "=DATEVALUE(MID(" & xlCellC.Address & ",1,10))+TIMEVALUE(MID(" & xlCellC.Address & ",12,8))"
If xlCellC.Offset(0, lCol + 1) - xlCellB.Offset(0, lCol + 1) >= ((1 / 24) / 4) Then
With xlCellA
.Value = xlCellC.Value
.Offset(0, 1).Value = xlCellC.Offset(0, 1).Value
End With
Set xlCellA = xlCellA.Offset(1, 0)
End If
Next j
Next i
Set xlCellA = Nothing
Set xlCellB = Nothing
Set xlCellC = Nothing
End Sub
Private Function FixFormat(ByVal dStr As String) As String
Dim tmpStr As String
Dim i As Integer
For i = 1 To Len(dStr)
If Mid(dStr, i, 1) <> "." Then
tmpStr = tmpStr & Mid(dStr, i, 1)
Else
If Mid(dStr, i + 1, 1) <> " " Then tmpStr = tmpStr & "-"
End If
Next i
FixFormat = tmpStr
End Function
It's not really clear what needs to happen when the 15min threshold is met but this should get you most of the way there:
Sub stackoverflow()
Dim w As Long, Timediff As Double
Dim wb As Workbook, wsData As Worksheet, wsResults As Worksheet, col As Long
Dim baseRow As Range, dataRow As Range, rngData As Range, resultRow As Range
Timediff = 1 / 24 / 4 '(15min = 1/4 of 1/24 of a day)
Set wb = ActiveWorkbook 'or ThisWorkbook
Set wsResults = wb.Worksheets("Results")
'first row for recording results
Set resultRow = wsResults.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow
For w = 3 To wb.Worksheets.Count 'for every sheet from the 3rd to the last
Set rngData = wb.Worksheets(w).Range("A1").CurrentRegion 'whole table
Set rngData = rngData.Offset(1, 0).Resize(rngData.Rows.Count - 1) 'exclude headers
Set baseRow = rngData.Rows(1) 'set comparison row
For Each dataRow In rngData.Rows 'loop over rows in data
If (dataRow.Cells(1).Value - baseRow.Cells(1).Value) > Timediff Then
resultRow.Cells(1).Value = dataRow.Cells(1) 'copy date
For col = 2 To dataRow.Cells.Count 'loop columns and subtract
resultRow.Cells(col).Value = _
dataRow.Cells(col).Value - baseRow.Cells(col).Value
Next col
Set resultRow = resultRow.Offset(1, 0)
Set baseRow = dataRow.Offset(1, 0) 'reset comparison row to next row
End If
Next dataRow
Next w
End Sub

VBA loop until the last column and increase value in column by 1

I am working on a project where I need to populate the column headings with incremental values (increased by 1) until the Last Column.
The code is working OK but the value in the column headings is NOT increased by 1. It is just taking the original value and place it over all columns.
Could you help me?
My code so far:
Sub LastColumn_PopulateHeadings()
'Declare variable for Last row (Prior FY)
Dim LastColumn As Integer
Dim i As Integer
'Find the last Column used
LastColumn = Range("XFD4").End(xlToLeft).Column
'populate headings with column values UNTIL LAST COLUMN
' Loop to populate the heading until LAST column
i = 8
Do While i < LastColumn
'MsgBox (LastColumn)
Cells(4, i).Value = Cells(4, i).Value + 1
i = i + 1
Loop
End Sub
I find your code a little strange, but probably i am missing something. Anyway this one should work:
Sub LastColumn_PopulateHeadings()
'Declare variable for Last row (Prior FY)
Dim LastColumn As Integer
Dim i As Integer
Dim IntCounter01 As Integer '<<<<<<ADDED LINE (1 of 3)
'Find the last Column used
LastColumn = Range("XFD4").End(xlToLeft).Column
'populate headings with column values UNTIL LAST COLUMN
' Loop to populate the heading until LAST column
i = 8
IntCounter01 = 1 '<<<<<<ADDED LINE (2 of 3)
Do While i < LastColumn
'MsgBox (LastColumn)
Cells(4, i).Value = IntCounter01
i = i + 1
IntCounter01 = IntCounter01 + 1 '<<<<<<ADDED LINE (3 of 3)
Loop
End Sub
I took your code and added 3 lines. You could also use a For-Next cycle instead of using a Do-While-Loop cycle since you already know your maximal value. Something like:
For i = i To LastColumn - 1
Cells(4, i).Value = IntCounter01
IntCounter01 = IntCounter01 + 1
Next
You could also use a formula to cover your range instead of picking each cell one by one. Like this:
Sub LastColumn_PopulateHeadings()
'Declarations.
Dim IntFirstColumn As Integer
Dim IntLastColumn As Integer
Dim IntRow As Integer
Dim IntFirstValue
Dim RngRange01 As Range
'Setting variables.
IntFirstValue = 1
IntRow = 4
IntFirstColumn = 8
IntLastColumn = Range("XFD4").End(xlToLeft).Column
'Setting first value in the first cell.
Cells(IntRow, IntFirstColumn).Value = IntFirstValue
'Setting RngRange01.
Set RngRange01 = Range(Cells(IntRow, IntFirstColumn + 1), Cells(IntRow, IntLastColumn - 1))
'Setting formulas in RngRange01.
RngRange01.FormulaR1C1 = "=RC[-1]+1"
'Copy-pasting the values in RngRange01.
RngRange01.Value = RngRange01.Value
End Sub

How do you average values in a Do Until Loop?

I am attempting to write a code to average values in a particular column. I have a table with 5 columns, Column number 2 has the date/time, and column number 5 has a measurement. There are over 500 lines of data, one for each minute of the test, and my goal is to write a code to take all the data and average it down to 15 minute intervals.
I attempted this by starting my active cell on the first line of the table, and inserting a row, offsetting the active cell to take the value of the row below (date/time of minute 15) and move it into the newly inserted row. Then, to average the 15 rows of data for column 5 and input it into the inserted row in column 5. I attempted to do this with an iterative process but I cant get the macro to average the value.
Could someone please assist? - new to VBA, any help is appreciated.
Thanks
'Averages PID Values to 15 min intervals
Sub Make_Data_Box()
' Databoxes_1 Macro
Do Until IsEmpty(ActiveCell)
Dim loc As String
loc = ActiveCell.Value
Dim iter_1 As Integer
iter_1 = 1
Do Until ActiveCell.Value <> ActiveCell.Offset(iter_1, 0).Value
iter_1 = iter_1 + 1
Loop
ActiveCell.EntireRow.Insert
ActiveCell.Offset(iter_1, 1).Select
ActiveCell.Offset(-iter_1, 0).Value = ActiveCell.Value
ActiveCell.Offset(iter_1 - 1, 2).Select
ActiveCell.Value = Application.WorksheetFunction.Average(Range("ActiveCell:ActiveCell - 14"))
' ActiveSheet.Range(ActiveCell) = Application.WorksheetFunction.Average(ActiveSheet.Range("ActiveCell:ActiveCell+14"))
ActiveCell.Offset(-iter_1 + 1, 0).Value = ActiveCell.Value
ActiveCell.Offset(iter_1 + 14, -2).Select
Loop
End Sub
Sub Make_Data_Box()
Dim ws As Worksheet
Dim rngData As Range
Dim rngAvg As Range
Dim idx As Long
Dim AvgCol As Long
Dim DataCol As Long
Dim AveragePeriod As Long
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Set ws = ActiveSheet ' or specify sheet you want
' Get reference to Data Values range, this assume there are Headers in Row 1, Data from Row 2
DataCol = 5 ' Column number containing data
Set rngData = ws.Range(ws.Cells(2, DataCol), ws.Cells(ws.Rows.Count, DataCol).End(xlUp))
' Column to put Average in
AvgCol = 6 ' adjust to place Average where you want it
AveragePeriod = 15 ' Take average of this number of rows
For idx = AveragePeriod To rngData.Rows.Count Step AveragePeriod ' fill every AveragePeriod cell with average
rngData.EntireRow.Cells(idx, AvgCol) = _
WorksheetFunction.Average(rngData.Cells(idx, 1).Offset(1 - AveragePeriod, 0).Resize(AveragePeriod, 1))
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Or, if you want to insert a row for the AVERAGES, work from the bottom up
Sub Make_Data_Box2()
Dim ws As Worksheet
Dim rngData As Range
Dim rngAvg As Range
Dim idx As Long
Dim AvgCol As Long
Dim DataCol As Long
Dim AveragePeriod As Long
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Set ws = ActiveSheet ' or specify sheet you want
' Get reference to Data Values range, this assume there are Headers in Row 1, Data from Row 2
DataCol = 5 ' Column number containing data
Set rngData = ws.Range(ws.Cells(2, DataCol), ws.Cells(ws.Rows.Count, DataCol).End(xlUp))
' Column to put Average in
AvgCol = 6 ' adjust to place Average where you want it
AveragePeriod = 15 ' Take average of this number of rows
For idx = (rngData.Rows.Count \ 15) * 15 To 1 Step -AveragePeriod ' fill every 15th cell with average
With rngData.Cells(idx, 1)
.EntireRow.Insert
.Offset(-1, AvgCol - DataCol) = _
WorksheetFunction.Average(.Offset(-AveragePeriod, 0).Resize(AveragePeriod, 1))
End With
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Finding a text string yyyymm based on current year and month

I need to locate all cells within column L starting from Row 10 containing yyyymm+2 (202009).
In other words, I'm looking for cells containing all dates belonging to the month 2 months in advance of the current month. Valid values would be 20200901 up until 20200930 accordingly as of July 2020.
The Column L contains values in text format such as 20201120, 20210102, etc. All the values are dates in Column L formatted as text as 'yyyymmdd'.
I'm trying to use the code below, but it is quite clearly wrong, since +2 won't show the correct year or month if the year changes.
Dim strSearchText As String
Dim y As Integer
Dim m As Integer
m = DatePart("mm", Date) + 2
y = DatePart("yyyy", Date)
strSearchText = y & m
Dim rngSearchArea As Range
Set rngSearchArea = ws.Range(Range("L10"), ws.Range("L" & ws.Range("L:L").Cells.Count).End(xlUp))
Any ideas how to solve this?
Maybe you are just looking for something like that?
String containing today + 2 months in the yyyydd format:
str = Format(DateAdd("m", 2, Now()), "yyyymm")
Please test the next code. Since you did not answer my above question, it will return the range of processed dates in the column N:N, starting from the tenth row:
Sub GetDateTwoMonthMore()
Dim sh As Worksheet, arr As Variant, arrF As Variant, lastRow As Long
Dim El As Variant, k As Long, currMonth As Long
Set sh = ActiveSheet 'use here your sheet
lastRow = sh.Range("L" & Rows.count).End(xlUp).row
currMonth = CLng(Month(Date)) 'the current month reference
arr = sh.Range("L10:L" & lastRow).Value 'load the range to be processed in an array
ReDim arrF(1 To UBound(arr, 1)) 'Redim the final array at the initial dimension of all the range rows
For Each El In arr
If CLng(Mid(El, 5, 2)) = currMonth + 2 Then
'If CLng(Month(El)) = currMonth + 2 Then 'if your cells are date formatted...
k = k + 1: arrF(k) = El 'fill the final array with the appropriate dates
End If
Next
ReDim Preserve arrF(k) 'Keep only the non empty array elements
'Drop the array content in the columnn N:N, at once:
sh.Range("N10").Resize(UBound(arrF)).Value = WorksheetFunction.Transpose(arrF)
End Sub
If your L:L range is Date formatted, you must only comment/delete the line
If CLng(Mid(El, 5, 2)) = currMonth + 2 Then
and un-comment the next one...
Rather than converting and finding the current date into text, it is more accurate to convert the data of cells based on the current date to date data to compare.
Sub testDate()
Dim y As Integer, y1 As String
Dim m As Integer, m1 As String, d1 As String
Dim sDate As Date, eDate As Date
Dim TargetDay As Date
Dim rngDB As Range, rng As Range
Dim Ws As Worksheet
Set Ws = ActiveSheet
y = Year(Date)
m = Month(Date)
sDate = DateSerial(y, m + 2, 1)
eDate = DateSerial(y, m + 3, 0) 'Last day
With Ws
Set rngDB = .Range(Range("L10"), .Range("L" & Rows.Count).End(xlUp))
End With
For Each rng In rngDB
y1 = Left(rng, 4)
m1 = Mid(rng, 5, 2)
d1 = Right(rng, 2)
TargetDay = DateSerial(y1, m1, d1)
If TargetDay >= sDate And TargetDay <= eDate Then
Debug.Print rng.Address(0, 0, xlA1)
End If
Next rng
End Sub

EXCEL VBA copy data from a week into a different sheet

I have 2 sheets in a workbook, one has all the data ("hdagarb") and the other is "summary". In the data sheet, column 2 has names and column 5 has dates. These are the columns I'm concerned with. I want to get all the rows which fall within say week ending 9th of June, and copy the name in column 2 and the date in column 5 and paste it into my summary sheet. At the moment I can't even get it to copy and paste the column 2 names. Here is my code:
Sub finddata()
Dim todaysdate As Date
Dim thisweek As Date
Dim lastweek As Date
Dim finalrow As Long
Dim Rdate As Date
Dim i As Long
Sheets("Summary").Range("H5:H1000").ClearContents
todaysdate = Date
thisweek = (7 - Weekday(todaysdate, vbSaturday)) + todaysdate
lastweek = (7 - Weekday(todaysdate, vbSaturday)) + todaysdate - 7
finalrow = Sheets("HDAGarb").Range("A100000").End(xlUp).Row
For i = 2 To finalrow
Rdate = Sheets("hdagarb").Cells(i, 5)
If Rdate > lastweek Then
Sheets("hdagarb").Cells(i, 2).Copy
Sheets("Summary").Range("H100").End(xlUp).Offset(1, 0).PasteSpecial xlPasteFormulasAndNumberFormats
End If
Next i
Worksheets("summary").Activate
Worksheets("summary").Range("H5").Select
End Sub
The source data in column 5 is like this
02-Jun-2017
-
-
-
-
12-Apr-2017
01-May-2017
I want the script to ignore the entries without dates ("-").
The following code will only perform the copy if there is a valid date in column E:
Sub finddata()
Dim todaysdate As Date
Dim thisweek As Date
Dim lastweek As Date
Dim finalrow As Long
Dim newRow As Long
Dim Rdate As Date
Dim i As Long
Dim srcSheet As Worksheet
Dim dstSheet As Worksheet
todaysdate = Date
thisweek = (7 - Weekday(todaysdate, vbSaturday)) + todaysdate
lastweek = (7 - Weekday(todaysdate, vbSaturday)) + todaysdate - 7
Set srcSheet = Worksheets("HDAGarb")
Set dstSheet = Worksheets("Summary")
finalrow = srcSheet.Range("A" & srcSheet.Rows.Count).End(xlUp).Row
dstSheet.Range("H5:H" & dstSheet.Cells(dstSheet.Rows.Count, "H").End(xlUp).Row).ClearContents
newRow = 4
For i = 2 To finalrow
If IsDate(srcSheet.Cells(i, "E").Value) Then
Rdate = CDate(srcSheet.Cells(i, 5).Value)
If Rdate > lastweek Then 'or If Rdate > lastweek And Rdate <= thisweek Then '???
newRow = newRow + 1
srcSheet.Cells(i, "B").Copy
dstSheet.Cells(newRow, "H").PasteSpecial xlPasteFormulasAndNumberFormats
'Not sure whether you wanted the next two lines
srcSheet.Cells(i, "E").Copy
dstSheet.Cells(newRow, "I").PasteSpecial xlPasteFormulasAndNumberFormats
End If
End If
Next i
dstSheet.Activate
dstSheet.Range("H5").Select
End Sub
I also changed it to keep track of the row being written to in the Summary sheet so that, if one of the names in the HDAGarb sheet was blank, it would still copy it and the associated date. (It's also faster if you don't have to keep recalculating which is the last row.)

Resources