VBA Repeatd summing up of hours until certain criterion - vba

I have a table with 6 columns. [ID, Status, Start Time, End Time, Hours, Sum UP]
I have counted a total amount hours between Start Time and End Time.
Now I have to count a Sum Up of this hours.
The problem is, that the sum up must be counted in a special range, starting from status "Shipped" until status "Checked" appears for only the first time. Then repeat starting again with "Shipped" until "Checked" for the next ID.
Sub SUMUP()
Dim LastRow As Long
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
Cells(i, 6).Value = WorksheetFunction.SumIf(Range("A2:A" & LastRow), Range("A" & i), Range("E2:E" & LastRow))
Next
End Sub
I have this code to sum up a total amount of hours. How can I write a VBA code for my case?
Thank you in advance for your help.

Try this one:
Sub SUMUP()
Dim LastRow As Long
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If Range("B" & i).Value = "Shipped" Then
For j = i To LastRow
If Range("B" & j).Value <> "Checked" Then
Sum = Sum + Range("E" & j).Value
Else
Range("F" & j).Value = Sum
Exit For
End If
Next j
i = j
Sum = 0
End If
Next i
End Sub

or an array
=SUM(INDIRECT(("f"&MIN(IF((($A$1:$A$10="ID")*($B$1:$B$10="shipped")),ROW($A$1:$A$10)))&":"&"f"&MIN(IF((($A$1:$A$10=1)*($B$1:$B$10="checked")),ROW($A$1:$A$10))))))

you could use this formula, if the order Status is sorted in the correct order:
=SUMIF(INDIRECT("A"&MATCH(A2,A:A,0)&":A"&ROW(A2)),A2,INDIRECT("E"&MATCH(A2,A:A,0)&":E"&ROW(A2)))
This would be an vba solution
Sub SUMUP()
Dim LastRow As Long
Dim hours As Integer
Dim ID As Integer
Dim checked As Boolean
LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
ID = Cells(2, 1).Value
For i = 2 To LastRow
If ID = Cells(i, 1).Value Then
If Cells(i, 2).Value <> "checked" And checked = False Then
hours = Cells(i, 6).Value + hours
Cells(i, 10).Value = hours
ElseIf Cells(i, 2).Value = "checked" And checked = False Then
checked = True
hours = Cells(i, 6).Value + hours
Cells(i, 10).Value = hours
End If
Else
ID = Cells(i, 1).Value
checked = False
hours = 0
End If
Next
End Sub

Just for completeness, I believe this non-array formula should work:-
=IF(AND(B2="checked",COUNTIFS(A$1:A2,A2,B$1:B2,"checked")=1),C2-INDEX(C$2:C$10,MATCH(A2&"shipped",INDEX(A$2:A$12&B$2:B$12,0),0)),"")
It just subtracts shipped datetime from first checked datetime.
Multiply by 24 to get the time in hours.

Related

VBA code to find sum of a particular column based on a particular column in excel

CHEQUE_NUMBER TC_Group NET_AMOUNT
A00147892 Food 2650
A00147892 Tax 250.43
A00147892 Tax 250.43
A00147892 Tips 132.5
A00147892 pay 3283.36
I want to calculate Net_Amount based on TC_Group='food' using cheque_number as base criteria using VB code
i.e Output would be of the form:
CHEQUE_NUMBER TC_Group NET_AMOUNT
A00147892 Food 2650
Let us assume that data appears in Sheet 1 as in the below image:
You could try:
Option Explicit
Sub Test()
Dim Lastrow As Long, i As Long, y As Long, LastrowList As Long, Lines As Long
Dim ChequeNo As String, Category As String
Dim Sum As Double
Category = "Food"
With ThisWorkbook.Worksheets("Sheet1")
'Find of Sheet1 & Column A lastrow
Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To Lastrow
If .Range("A" & i).Interior.Color <> 65535 Then
ChequeNo = .Range("A" & i).Value
Sum = .Range("C" & i).Value
For y = i + 1 To Lastrow
If .Range("A" & y).Interior.Color <> 65535 And .Range("A" & y).Value = ChequeNo And .Range("B" & y).Value = Category Then
Sum = Sum + .Range("C" & i).Value
With .Range("A" & y & ":C" & y).Interior
.Color = 65535
End With
End If
Next y
With .Range("A" & i & ":C" & i).Interior
.Color = 65535
End With
LastrowList = .Cells(.Rows.Count, "A").End(xlUp).Row
If Lastrow = LastrowList Then
Lines = 2
Else
Lines = 1
End If
.Cells(LastrowList + Lines, 1).Value = ChequeNo
.Cells(LastrowList + Lines, 2).Value = Category
.Cells(LastrowList + Lines, 3).Value = Sum
End If
Next i
End With
End Sub
Note: Checked value will be highlighted with yellow.

Count and Print from an range

I have an array of data, a screenshot of it will be linked at the bottom of this text. Row and column references are to the screenshot.
I am trying to write a macro that will output all the dates that occur within the dynamic range (Column H). And then in column I I want the column header # row i.e I4.
But if there is more than 1 count at the date, I would like the second school to output into column J. As it would for the date 26/03/18, looking like this:
h5 = 26/03/18 , i5(Event1) = Task 2 # 1, j5(Event2) = task 2 # 4
I have tried many ways today and would like some assistance.
Screenshot: https://ibb.co/cmiGSc
My Code thus far(For the more complex sheet):
Sub Events()
'How many schools there are
Dim sh As Worksheet
' This needs to change for each sheets
Set sh = ThisWorkbook.Sheets("Easter 18")
Dim k As Long
k = sh.Range("A3").End(xlDown).Row 'Counts up from bottow - Number of schools attained
Ro = Range("M52").value = k - 2 'Elimiates the two top rows as headers
'Now I need to search the Range of dates
Dim TaskDates As Range
Dim StartCell As Range 'First part of Array
Dim EndCell As Range 'End of Array
Set EndCell = Range("J" & 2 + k) 'maybe 2 or 3
Set StartCell = Range("G3")
Set TaskDates = Range(StartCell, EndCell) 'Dynamic Range
'Within the range of data print out the most left row header (school name) - and task with # in the middle - ascending
' If Column has date (true) create a table with Date (col 1), Event (col 2), Event 2 (Col3) etc etc
Dim dict As Object
Set dict = CreateObject("scripting.dictionary")
Dim varray As Variant, element As Variant
varray = TaskDates.value
'Generate unique list and count
For Each element In varray
If dict.exists(element) Then
dict.item(element) = dict.item(element) + 1
Else
dict.Add element, 1
End If
Next
'Paste report somewhere -
'First line ouptuts the dates occured
sh.Range("M55").Resize(dict.Count).value = 'Was working now saying syntax error for this line.
WorksheetFunction.Transpose (dict.keys)
' The count works if cell format is correct
CDates = sh.Range("N55").Resize(dict.Count, 1).value = _
WorksheetFunction.Transpose(dict.items)
End Sub
Please feel free to redesign it if you see fit.
you can go this way
Option Explicit
Sub Tasks()
Dim cell As Range, f As Range
With Worksheets("schools") 'change "schools" to your actual sheet name
For Each cell In .Range("C4:F" & .Cells(.Rows.Count, "B").End(xlUp).Row) 'reference its column C:F from row 4 down to column B last not empty cell
If IsDate(cell.value) Then 'if current cell value is a valid date
Set f = .Range("H3", .Cells(.Rows.Count, "H").End(xlUp)).Find(what:=cell.value, lookat:=xlWhole, LookIn:=xlValues) 'try finding the date in column H
If f Is Nothing Then Set f = .Cells(.Rows.Count, "H").End(xlUp).Offset(1) 'if date not already in column H then get its first empty cell after last not empty one
f.value = cell.value 'write the date (this is sometimes not necessary, but not to "ruin" the code)
.Cells(f.Row, .Columns.Count).End(xlToLeft).Offset(, 1).value = .Cells(3, cell.Column).value & " #" & .Cells(cell.Row, 2).value ' write the record in the first not empty cell in the "date" row
End If
Next
End With
End Sub
Took a shot at this. Just a couple nested loops testing against the dates, making sure that the date found isn't already listed under the date column. As I stated before, you never said what to do if more than 3 dates are found, so I had to add a fourth event column and assume that that's the max. Anything more than 4 dates won't be recorded anywhere, FYI.
Sub MoveDates()
Dim i As Long, j As Long, sht As Worksheet, lastrow As Long, lastrow2 As Long, refrow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
lastrow = sht.Cells(sht.Rows.Count, "B").End(xlUp).Row
lastrow2 = sht.Cells(sht.Rows.Count, "H").End(xlUp).Row + 1
For i = 4 To lastrow
For j = 3 To 6
If Cells(i, j).Value <> "" And Cells(i, j).Value <> "n/a" Then
If Not Application.WorksheetFunction.CountIf(Range("H4:H" & lastrow), Cells(i, j)) > 0 Then
lastrow2 = sht.Cells(sht.Rows.Count, "H").End(xlUp).Row + 1
Range("H" & lastrow2).Value = Cells(i, j).Value
If Range("I" & lastrow2).Value = "" Then
Range("I" & lastrow2).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("J" & lastrow2).Value = "" Then
Range("J" & lastrow2).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("K" & lastrow2).Value = "" Then
Range("K" & lastrow2).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("L" & lastrow2).Value = "" Then
Range("L" & lastrow2).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
End If
Else
lastrow2 = sht.Cells(sht.Rows.Count, "H").End(xlUp).Row
For k = 4 To lastrow2
If Range("H" & k).Value = Cells(i, j).Value Then
refrow = k
Exit For
End If
Next k
If Range("I" & refrow).Value = "" Then
Range("I" & refrow).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("J" & refrow).Value = "" Then
Range("J" & refrow).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("K" & refrow).Value = "" Then
Range("K" & refrow).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
ElseIf Range("L" & refrow).Value = "" Then
Range("L" & refrow).Value = Cells(3, j).Value & " # " & Cells(i, 2).Value
End If
End If
End If
Next j
Next i
End Sub

Moving to the next column

Can anybody please help me figure out my problem?
I have this code that I would like to move to the next column if the condition is not met.I'm stuck and don't know where to proceed.
Dim lrow3, lrow1 as long
dim dDate as Date
dim yrNum, j as Integer
dDate = Format(Now(),"mm/dd/yyyy")
lrow3 = ActiveSheet.Cells(Rows.count, 2).End(xlUp).Row
lrow1 = Sheets("Sample").Cells(Rows.count, 2).End(xlUp).Row
for j = 2 to lrow1
For yrNum = 1 To 100
If DateValue(Format(Range("Q" & j).Value, "mm/dd/yyyy")) >= DateValue(dDate) And _
DateValue(Format(Range("R" & j).Value, "mm/dd/yyyy")) <= DateValue(dDate) Then
ActiveSheet.Range("D" & lrow3 + 1).Value = Range("T" & j).Value
ActiveSheet.Range("E" & lrow3 + 1).Value = Range("U" & j).Value
Exit For
Else
Range("Q" & j) = ActiveCell
Range("Q" & j) = ActiveCell.Offset(0, 9)
'after executing this is I have to set this offsetted cell to be the active one
'on which i will be referring in the next loop
End If
Next yrNum
next j
In the snippet, if the value in Q & j does not met the requirements, then i have to check the 9th letter after Q which is Z and so on.
By the way what I'm comparing on this are date values in the cell.
A few observations
dDate = Format(Now(),"mm/dd/yyyy") is the same as dDate = Date
DateValue(Format(Range("Q" & j).Value, "mm/dd/yyyy")) is the same asDateValue(Range("Q" & j).Value)`
You are starting in column Q and if the conditions are not meet you move over 9 columns and check again. You do this 100 times. The final column is column 917(column letter code AIG)
Sub RefactoredCode()
Dim lrow3, lrow1 As Long
Dim DateRange As Range
Dim wsSample As Worksheet
Dim yrNum, j As Integer, iOffset As Integer
Set wsSample = Worksheets("Sample")
lrow3 = Cells(Rows.Count, 2).End(xlUp).Row
lrow1 = wsSample.Cells(Rows.Count, 2).End(xlUp).Row
For j = 2 To lrow1
For yrNum = 1 To 100
iOffset = (yrNum * 9) - 9
Set DateRange = wsSample.Cells(j, "Q").Offset(0, iOffset)
If DateValue(DateRange.Value) >= Date And _
DateValue(DateRange.Offset(0, 1).Value) <= Date Then
lrow3 = lrow3 + 1
Range("D" & lrow3).Value = wsSample.Cells(j, "T").Offset(0, iOffset).Value
Range("E" & lrow3).Value = wsSample.Cells(j, "U").Offset(0, iOffset).Value
Exit For
End If
Next yrNum
Next j
End Sub

Insert row in excel with a value in a specific cell

I'm using this script to insert fill with rows where non-sequential is produced in a column of an excel file.
Sub InsertValueBetween()
Dim lastrow As Long
Dim gap As Long
Dim i As Long, ii As Long
Application.ScreenUpdating = False
With ActiveSheet
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = lastrow To 3 Step -1
gap = .Cells(i, "A").Value - .Cells(i - 1, "A").Value
If gap > 1 Then
.Rows(i).Resize(gap - 1).Insert
End If
Next i
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Cells(3, "A").Value = .Cells(2, "A").Value + 1
.Cells(2, "A").Resize(2).AutoFill .Cells(2, "A").Resize(lastrow - 1)
End With
End Sub
In addition to adding these new rows I want them to also have a specific value in column B. I'm trying to implement this but with no result.
Anybody could help me?
One way you could tackle this challenge is with a Range variable. Here is some heavily-commented code that walks through the process:
Sub InsertValueBetweenRev2()
Dim Target As Range '<~ declare the range variable
'... declare your other variables
'... do other stuff
For i = lastrow To 3 Step -1
gap = .Cells(i, "A").Value - .Cells(i - 1, "A").Value
If gap > 1 Then
.Rows(i).Resize(gap - 1).Insert
'the next line sets the range variable to the recently
'added cells in column B
Set Target = .Range(.Cells(i, 2), .Cells(i + gap - 2, 2))
Target.Value = "Cool" '<~ this line writes text "Cool" into those cells
End If
Next i
'... the rest of your code
End Sub
So, to sum it up, we know that gap - 1 rows are going to be added, and we know that the new rows are added starting at row i. Using that knowledge, we assign the just-added cells in column B to a Range then set the .value of that Range to whatever is needed.
a Better way of doing it with less variables and faster:
Sub InsRowWithText()
Dim LR As Long, i As Long
LR = Range("D" & Rows.Count).End(xlUp).row
For i = LR To 3 Step -1
If Range("D" & i).Value <> Range("D" & i - 1).Value Then
Rows(i).Resize(1).Insert
Range("D" & i).Value = "Test"
End If
Next i
End Sub
This is how i utilized it:
Sub InsRowWithText()
Dim strMsg As String, strTitle As String
Dim LR As Long, i As Long
Text = "ADD"
strMsg = "Warning: This is a Advanced Function, Continue? "
strTitle = "Warning: Activated Advanced Function "
If MsgBox(strMsg, vbQuestion + vbYesNo, strTitle) = vbNo Then
Exit Sub
Else
Sheets("SAP Output DATA").Select
If Range("D3").Value = Text Then
MsgBox "Detected That This Step Was Already Completed, Exiting."
Exit Sub
End If
application.ScreenUpdating = False
LR = Range("D" & Rows.Count).End(xlUp).row
For i = LR To 3 Step -1
If Range("D" & i).Value <> Range("D" & i - 1).Value Then
Rows(i).Resize(1).Insert
Range("D" & i).EntireRow.Interior.ColorIndex = xlColorIndexNone
Range(("A" & i), ("D" & i)).Value = Text
End If
Next i
End If
Range("D2").Select
Selection.End(xlDown).Select
ActiveCell.Offset(1).Select
Range(("A" & ActiveCell.row), ("D" & ActiveCell.row)).Value = Text 'last row doesnt get text for some reason.
ActiveCell.EntireRow.Interior.ColorIndex = xlColorIndexNone
ActiveCell.Offset(1).Select
Range(("D" & ActiveCell.row), ("E" & ActiveCell.row)).Interior.ColorIndex = 17 'purple
application.ScreenUpdating = True
Range("D3").Select
End Sub

comparing a single value against an array in VBA

Sub CHECKas()
Dim lastrow As Long
Dim lastcol As Long
Dim l As Integer
Dim i As Integer
Dim rname As Constants
Set rngTarg = Selection
lastrow = Sheets("report").Range("B" & Rows.Count).End(xlUp).row
lastcol = Sheets("report").Cells(2, Columns.Count).End(xlToLeft).Column
Sheets("FEBBRAIO").Select
ActiveCell.Offset(0, -3).Copy
Sheets("REPORT").Select
Cells(1, lastcol + 1).PasteSpecial xlPasteAll
Application.CutCopyMode = False
rname = Application.ActiveCell.Value
ActiveCell.Offset(1, 0).Select
For i = 2 To lastrow
ThisWorkbook.Sheets("report").Select
If Range("f2:f" & lastrow) <= Val(CStr(rname.Value)) _
And Range("g2:g" & lastrow) > Val(CStr(rname.Value)) Then
Cells(i, ActiveCell.Column).Value = "1"
Else
Cells(i, ActiveCell.Column).Value = 0
End If
Next i
End Sub
I'm new in VBA and I can't understand how to compare a constant value with each cell in a range("g2:g" & lastrow) and ("f2:f" & lastrow). The constant value is an active cell in my case. For example considering this formula: IF(AND($R$1<G2;$R$1>=f2);1;0 where R$1$ is the active cell of the last not empty column in ROW 1. I need to fill the entire column (that is activecell.column) with the output coming out form this formula.
But the I Got mismatch error in:
If Range("f2:f" & lastrow) <= Val(CStr(rname.Value)) _
And Range("g2:g" & lastrow) > Val(CStr(rname.Value)) Then
Cells(i, ActiveCell.Column).Value = "1"
Else
Cells(i, ActiveCell.Column).Value = 0
End If
I know from the previous question that this error occurs because I'm trying to comparing a single value against an array of values. How can fix this problem?
You have to use
Range("F" & i)
in your code. Same thing applies to other instances of such code.