VBA macro takes too long to execute - excel

This very simple macro is taking 93 seconds just run through 55 iterations. I also tried it as a for next loop, same result.
Dim thedate As Date
Dim current_cell As Long
Dim f As Single
f = Timer()
current_cell = Range("e65000").End(xlUp).Row
thedate = Range("e" & current_cell).Value
Dim i As Integer
Application.ScreenUpdating = False
Do Until Range("f" & current_cell).Value = ""
i = i + 1
If i = 900 Then
End
End If
If Range("g" & current_cell).Value <> "x" Then
Cells(current_cell, "e").Value = thedate
Else
thedate = thedate + 1
Cells(current_cell, "e").Value = thedate
End If
current_cell = current_cell + 1
Loop
Application.ScreenUpdating = True
MsgBox "ET: " & Format(Timer - f, "0.000") & "s"
FIRST UPDATE
Ok, I looked at another page and they recommended using the with feature. I did that and it still took me 28 seconds to loop through 15 cells.
Dim thedate As Date
Dim current_cell As Long
Dim f As Single
f = Timer()
current_cell = Range("e65000").End(xlUp).Row
Dim stop_working As Long
stop_working = Range("f65000").End(xlUp).Row - 1
thedate = Range("e" & current_cell).Value
Dim i As Integer
Application.ScreenUpdating = False
With Sheets("time")
For k = current_cell To stop_working
i = i + 1
If i = 900 Then
End
End If
If .Range("g" & current_cell).Value <> "x" Then
.Cells(current_cell, "e").Value = thedate
Else
thedate = thedate + 1
.Cells(current_cell, "e").Value = thedate
End If
current_cell = current_cell + 1
Next
End With
Application.ScreenUpdating = True
MsgBox "ET: " & Format(Timer - f, "0.000") & "s"
THIRD UPDATE
Ok, I've done some research and I learned that you're not supposed to loop over ranges and that you're supposed to put the ranges in an array. I don't really understand this but I did try putting the cells into an array and using the for each feature. It still seems like I'm looping over ranges because whenever a step into the function it still noticeably takes a very long time to cross over the rng part of the code. My second problem is that none of the values are getting published on the screen. My third problem is that I'm getting a type mismatch with thedate. My fourth problem is that I don't understand the difference betwene value and value2.
Sub dates()
Dim thedate
Dim current_cell As Long
Dim f As Single
f = Timer()
Dim rng As Range, rng2 As Range
current_cell = Range("e65000").End(xlUp).Row
Dim done As Long
done = Range("f65000").End(xlUp).Row - 1
Set rng = Range("g" & current_cell, "g" & done)
Set rng2 = Range("e" & current_cell, "e" & done)
thedate = Format(thedate, Date)
thedate = rng2.Value
'thedate = rng2.Value
Dim i As Integer
i = 7
'Application.ScreenUpdating = False
'With Sheets("time")
For Each cell In rng
If cell.Value <> "x" Then
rng2.Value = thedate
Else
thedate = thedate + 1
rng2.Value = thedate
End If
Next
'End With
'Application.ScreenUpdating = True
MsgBox "ET: " & Format(Timer - f, "0.000") & "s"
4TH UPDATE
I have a new code that works but it still take 78 seconds to run through 50 iterations. Don't understand what the problem is.
Dim iRow As Long, erow As Long
erow = Cells(Rows.Count, "e").End(xlUp).Row
Dim thedate As Date
Dim f As Single
f = Timer()
For iRow = erow To 35856
If Cells(iRow, "G") = "x" Then
Cells(iRow, "E").Value = Cells(iRow - 1, "E").Value + 1
Else
Cells(iRow, "E").Value = Cells(iRow - 1, "E").Value
End If
Next iRow
MsgBox "ET: " & Format(Timer - f, "0.000") & "s"
End Sub

Problem solved. I need to change calculation to manual and disable the firing of events.
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
For iRow = 3 To Cells(Rows.Count, "G").End(xlUp).Row
If Cells(iRow, "G") = "x" Then
Cells(iRow, "E").Value = Cells(iRow - 1, "E").Value + 1
Else
Cells(iRow, "E").Value = Cells(iRow - 1, "E").Value
End If
Next iRow
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True

Related

Convert date list into date ranges [duplicate]

I have a data like this :
A049
A050
A051
A053
A054
A055
A056
A062
A064
A065
A066
And I want the output like :
As you can see, I want the ranges which are in consecutive order
I am trying some thing like this:
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
For i = 2 To lastRow
r = wb.Sheets("Sheet1").Range("A" & i).Value
If wb.Sheets("Sheet1").Range("A" & i).Value = wb.Sheets("Sheet1").Range("A" & i+1).Value
Next i
End Sub
But not helping me
Am feeling charitable so have tried some code which should work. It assumes your starting values are in A1 down and puts results in C1 down.
Sub x()
Dim v1, v2(), i As Long, j As Long
v1 = Range("A1", Range("A" & Rows.Count).End(xlUp)).Value
ReDim v2(1 To UBound(v1, 1), 1 To 2)
For i = LBound(v1, 1) To UBound(v1, 1)
j = j + 1
v2(j, 1) = v1(i, 1)
If i <> UBound(v1, 1) Then
Do While Val(Right(v1(i + 1, 1), 3)) = Val(Right(v1(i, 1), 3)) + 1
i = i + 1
If i = UBound(v1, 1) Then
v2(j, 2) = v1(i, 1)
Exit Do
End If
Loop
End If
If v1(i, 1) <> v2(j, 1) Then v2(j, 2) = v1(i, 1)
Next i
Range("C1").Resize(j, 2) = v2
End Sub
Try the below code
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
Dim lastNum, Binsert As Integer
Dim firstCell, lastCell, currentCell As String
Binsert = 1
lastNum = getNum(wb.Sheets("Sheet1").Range("A1").Value)
firstCell = wb.Sheets("Sheet1").Range("A1").Value
For i = 2 To lastRow
activeNum = getNum(wb.Sheets("Sheet1").Range("A" & i).Value)
currentCell = wb.Sheets("Sheet1").Range("A" & i).Value
If (activeNum - lastNum) = 1 Then
'nothing
Else
lastCell = wb.Sheets("Sheet1").Range("A" & (i - 1)).Value
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> lastCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = lastCell
End If
Binsert = Binsert + 1
firstCell = wb.Sheets("Sheet1").Range("A" & i).Value
End If
lastNum = activeNum
Next i
'last entry
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> currentCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = currentCell
End If
End Sub
Public Function getNum(ByVal num As String) As Integer
getNum = Val(Mid(num, 2))
End Function
Another solution. It loops backwards from last row to first row.
Option Explicit
Public Sub FindConsecutiveValues()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lRow As Long 'find last row
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Dim lVal As String 'remember last value (stop value)
lVal = ws.Range("A" & lRow).Value
Const fRow As Long = 2 'define first data row
Dim i As Long
For i = lRow To fRow Step -1 'loop from last row to first row backwards
Dim iVal As Long
iVal = Val(Right(ws.Range("A" & i).Value, Len(ws.Range("A" & i).Value) - 1)) 'get value of row i without A so we can calculate
Dim bVal As Long
bVal = 0 'reset value
If i <> fRow Then 'if we are on the first row there is no value before
bVal = Val(Right(ws.Range("A" & i - 1).Value, Len(ws.Range("A" & i - 1).Value) - 1)) 'get value of row i-1 without A
End If
If iVal - 1 = bVal Then
ws.Rows(i).Delete 'delete current row
Else
If lVal <> ws.Range("A" & i).Value Then 'if start and stop value are not the same …
ws.Range("B" & i).Value = lVal 'write stop value in column B
End If
lVal = ws.Range("A" & i - 1).Value 'remember now stop value
End If
Next i
End Sub

VBA Time Sheet and dealing with Lunch breaks

I have the workbook below that shows clock in and out each day for each employee and shop. I was able to find the cell and if they are late after 8:00 am then it will debug.print that the employee was late. The problem I have now is that sometimes the employee goes on a lunch break and its reading the second time clocked in as if he was late. I would like to print notes on the sheet that will tell me for example "Nathan was late on Monday, 8:47:43 AM" and if he left during the day and came back. For example "Trent left Monday on 12:54 PM and came back on 1:28 PM". I am just having trouble reading through multiple times on the same day. The below code is what I have so far. Any ideas?
Sheet :
Sub TestFindAll()
Dim SearchRange As Range
Dim FindWhat As Variant
Dim FoundCells As Range
Dim FoundCell As Range
Dim LastRowA As Long, LastRowJ As Long
Dim WS1 As Worksheet
Set WS1 = ThisWorkbook.Worksheets("DailyTimeSheet")
LastRowJ = WS1.Range("J" & WS1.Rows.Count).End(xlUp).Row
Debug.Print LastRowJ
Dim firstAddress As String
With WS1
Dim tbl As ListObject: Set tbl = .Range("DailyTime").ListObject
Set SearchRange = tbl.ListColumns("EmployeeName").Range
End With
For t = 2 To LastRowJ
FindWhat = WS1.Range("J" & t)
Set FoundCells = SearchRange.Find(What:=FindWhat, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows)
If Not FoundCells Is Nothing Then
firstAddress = FoundCells.Address
Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2).Value
Do
If Not FoundCells.Offset(0, 2).Value = "Sat" And FoundCells.Offset(0, 5).Value < TimeValue("18:00:00") Then
Debug.Print FoundCells.Value & " left early on " & FoundCells.Offset(0, 2) & " at " & TimeValue(Format(FoundCells.Offset(0, 5).Value, "hh:mm:ss"))
End If
Set FoundCells = SearchRange.FindNext(FoundCells)
' Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2)
Loop While Not FoundCells Is Nothing And FoundCells.Address <> firstAddress
End If
Next
End Sub
Use a Dictionary Object with names as key to identify the first in or last out time of the day.
Option Explicit
Sub macro()
Dim lastrow As Long, r As Long, dt As String
Dim dict As Object, key, n As Long, c As Range
Set dict = CreateObject("Scripting.Dictionary")
With Sheet1 'ThisWorkbook.Worksheets("DailyTimeSheet")
.Cells.Interior.Pattern = xlNone
lastrow = .Cells(.Rows.Count, "J").End(xlUp).Row
' check in times
For Each c In .Range("J2:J" & lastrow).Cells
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
' is this first for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
c.Offset(, 4) > TimeValue("08:00:00") Then
c.Offset(, 4).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
' reverse scan to check out times
dict.RemoveAll
For r = lastrow To 2 Step -1
Set c = .Cells(r, "J")
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
'is the last for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
(c.Offset(, 5) < TimeValue("18:00:00")) Then
c.Offset(, 5).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
MsgBox n & " cells highlighted", vbInformation
End With
End Sub

how to copy an entire row to sheet 2 if column H has a date in cell.?

I am trying to search (if column H in sheet mechanical Equip. has any date then copy entire row to sheet off rent next available row. It is coping the first row from mechanical equip. whether it has a date or not.
Sub CopyRowWithDates()
Dim lrowcompleted As String
Dim Rrange As Range
Set Rrange = Sheets("MECHANICAL EQUIP.").Range("H2:H6000")
On Error Resume Next
Application.EnableEvents = False
If Rrange = "mm/dd/yyy" Then
lrowcompleted = Sheets("OFF RENT").Cells(Rows.Count, "A").End(xlUp).ROW
Range("A" & Rrange.ROW & ":N" & Rrange.ROW).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
Else
End If
Application.EnableEvents = True
End Sub
If you use For each myDate in range("H2:H6000") instead of set range?
Sub CopyRowWithDates()
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim lrowcompleted As String
Dim myDate as String
For each myDate in range("H2:H6000")
On Error Resume Next
Application.EnableEvents = False
If myDate = "mm/dd/yyy" Then
lrowcompleted = Sheets("OFF RENT").Cells(Rows.Count, "A").End(xlUp).ROW
Range("A" & myDate.ROW & ":N" & myDate.ROW).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
Else
End If
Application.EnableEvents = True
Application.Screenupdating = True
End Sub
I prefer to use Range("A1048576").End(xlUp).Rowinstead of Cells(Rows.Count,"A").End(xlUp).ROW
i modified a different code i had and this one works the way i need it to. thanks for help.
Private Sub CommandButton5_Click()
Dim id As String
Dim PO As String
Dim finalrow As Integer
Dim i As Integer
Dim lrowcompleted As String
id = TextBox19.Value
finalrow = Sheets("ALL P.O. INFO").Range("D6000").End(xlUp).row
For i = 2 To finalrow
If Sheets("ALL P.O. INFO").Cells(i, 4) = id Then
Sheets("ALL P.O. INFO").Cells(i, 8).Value = TextBox17.Value
End If
If Sheets("MECHANICAL EQUIP.").Cells(i, 4) = id Then
Sheets("MECHANICAL EQUIP.").Cells(i, 8).Value = TextBox17.Value
lrowcompleted = Sheets("OFF RENT").Range("A6000").End(xlUp).row
Sheets("MECHANICAL EQUIP.").Range("A" & i & ":N" & i).Copy Sheets("OFF RENT").Range("A" & lrowcompleted + 1)
End If

Get values on a row based on two or more rows in Excel

I have values in DEMAND row and values in the COLLECTION row, now I want BALANCE = DEMAND-COLLECTION, there are two times collection for an entry so according to the occurrence of collection the balance should arise. Can you please let me know the macro code for that.
I have DEMAND values D1:S1 COLLECTION values from D2:S2 and the balance should be there in the next row.
I came to this step after the solution I got from
Insert row base on specific text and its occurrence
I am using the following code
Sub try()
Dim c As Range
Dim lRow As Long
lRow = 1
Dim lRowLast As Long
Dim bFound As Boolean
With ActiveSheet
lRowLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Do
Set c = .Range("A" & lRow)
If c.Value Like "*COLLECTION*" Then
bFound = True
ElseIf bFound Then
bFound = False
If c.Value <> "BALANCE" Then
c.EntireRow.Insert
lRowLast = lRowLast + 1
c.Offset(-1, 0).Value = "BALANCE"
c.Offset(-1, 0).Font.Color = RGB(0, 0, 0)
End If
End If
lRow = lRow + 1
Loop While lRow <= lRowLast + 1
End With
End Sub
before macro check IMAGE
After Macro I want this check image
So I would use SUMIF applied with FormulaR1C1 for that. The advantage is that we can set the formula in one step for the whole row.
Sub try()
Dim c As Range
Dim lRow As Long
lRow = 1
Dim lRowLast As Long
Dim lRowDiff As Long
Dim lRowPortion As Long
lRowPortion = 1
Dim bFoundCollection As Boolean
With ActiveSheet
lRowLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Do
Set c = .Range("A" & lRow)
If c.Value Like "*COLLECTION*" Then
bFoundCollection = True
ElseIf bFoundCollection Then
bFoundCollection = False
If c.Value <> "BALANCE" Then
c.EntireRow.Insert
lRowLast = lRowLast + 1
Set c = c.Offset(-1, 0)
c.Value = "BALANCE"
End If
If c.Value = "BALANCE" Then
.Range(c, c.Offset(0, 18)).Font.Color = RGB(0, 0, 0)
.Range(c, c.Offset(0, 18)).Interior.Color = RGB(200, 200, 200)
lRowDiff = c.Row - lRowPortion
.Range(c.Offset(0, 3), c.Offset(0, 18)).FormulaR1C1 = _
"=SUMIF(R[-" & lRowDiff & "]C1:RC1, ""*DEMAND*"", R[-" & lRowDiff & "]C:RC)" & _
"-SUMIF(R[-" & lRowDiff & "]C1:RC1, ""*COLLECTION*"", R[-" & lRowDiff & "]C:RC)"
lRowPortion = c.Row + 1
End If
End If
lRow = lRow + 1
Loop While lRow <= lRowLast + 1
End With
End Sub

Changing VBA macro code to change number part 2

I have had to open a new question following a previous question i had to decrease and increment a number which is on the link bellow
Changing VBA macro code to change number
this is the code that i am trying to work with and i got it almost to work but somewhere its gone wrong.
Bulkwks.[B5] is M20
historywks.[a2] is the time
historywks.[b2] is the name
historywks.[C2] is m201001
Sub bulkON_Click()
Dim trnwkbk As Workbook
Dim Bulkwks As Worksheet
Dim Deswkbk As Workbook
Dim LogNum As Range, LastNum, NewNum,
Dim historywks As Worksheet
Dim nextRow As Long
Dim lOR As Long
Dim myIn As String
Dim myLeft As String
Dim myMid As Integer, myRight As Integer, i As Integer
Dim myOut As String
Set trnwkbk = Workbooks("Transport.xls")
Set Bulkwks = trnwkbk.Worksheets("Bulk")
lOR = MsgBox("Have you selected the right MIS or HUB or PSA number?", vbQuestion + vbYesNo, "Number Order")
If lOR = vbNo Then
MsgBox "Please select right Order Number"
Else
Application.ScreenUpdating = False
' for testing i just made it post in test sheet in same workbook
'Set Deswkbk = Workbooks.Open("\\dunton01\Inspections\TRANSPORT\New_transport\data\Febuary_2013.xls")
'Set historywks = Deswkbk.Worksheets("Data")
Set historywks = Worksheets("test")
Set LogNum = historywks.[C2]
With historywks
nextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
End With
If LogNum(2, 1) = "" Then
LastNum = LogNum
Else
LastNum = LogNum(LogNum.End(xlDown).Row - 1, 1)
End If
NewNum = Bulkwks.[B5] & Val(Mid(LastNum, 2)) + 1
If LogNum(2, 1) = "" Then
LogNum(2, 1) = NewNum
Else
myIn = LogNum
myLeft = Left(myIn, 1)
myMid = CInt(Mid(myIn, 2, 2))
myRight = CInt(Right(myIn, 4))
myOut = myLeft & Format(myMid, "00") & Format(myRight, "0000")
i = 0
Debug.Print "IN: " & myIn
Debug.Print "BROKEN UP: " & myOut
Do Until myMid = -1
Debug.Print "ITERATION " & Format(i, "00") & ": " & myLeft & Format(myMid, "00") & Format(myRight, "0000")
myMid = myMid - 1
myRight = myRight + 1
myOut = myLeft & Format(myMid, "00") & Format(myRight, "0000")
i = i + 1
With historywks
'enter date and time stamp in record
With .Cells(nextRow, "A")
.Value = Now
.NumberFormat = "mm/dd/yyyy hh:mm:ss"
End With
'enter user name in column B
.Cells(nextRow, "B").Value = Application.UserName
.Cells(nextRow, "C").Value = myIn
End With ' for testing i just disabled this Deswkbk.save
Loop
' for testing i just disabled this
'Deswkbk.Close savechanges:=True
Application.ScreenUpdating = True
Bulkwks.[E3] = NewNum
End If
' for testing i just disabled this
'Call File_In_Network_Folder
End If
End Sub
You'll need to use the myOut variable.
.Cells(nextRow, "C").Value = myOut

Resources