I have a code which builds a table based on the data in another sheet. In this sheet there are three columns - Time, URN and Location. Time is shown as HH:MM:SS, URN is a 4 digit number and Location is a postcode displayed in the usual format.
I have normally used this code with a Date instead of time, but I have been trying to use it with time. I have made a slight adjustment after declaring the date as a variable, adding in the time value part.
I am now getting a
Run-time error '91': Object variable or With block variable not set,
with the following highlighted:
.Cells(FndDt.Row, FndNum.Column) = "P"
I have tried removing this piece of code and adding in a On Error Resume Next but I then get an error on the lines above or below it.
Option Explicit
Sub chrisellis250()
Dim Dt, Urn, i As Long, x As Long, lr As Long, lc As Long: x = 2
Dim colwidth As Long
Dim FndDt As Range, FndNum As Range, Dat As Date, Num As String, Loc As String
Dat = TimeValue("00:00:00")
Application.ScreenUpdating = False
With Sheet2
lr = .Cells(.Rows.Count, 2).End(xlUp).Row
.Range(.Cells(2, 1), .Cells(.Rows.Count, 1)).AdvancedFilter xlFilterCopy, , .Range("E1"), True
With .Range("E1").CurrentRegion: Dt = .Value: End With
Sheet1.Range("A3").Resize(UBound(Dt) - 1) = .Range("E2:E" & UBound(Dt)).Value: .Columns(5).Clear
Sheet1.Range("A3").Resize(UBound(Dt) - 1).Interior.ColorIndex = 15
.Range(.Cells(2, 2), .Cells(.Rows.Count, 2)).AdvancedFilter xlFilterCopy, , .Range("E1"), True
With .Range("E1").CurrentRegion: Urn = .Value: End With
For i = 1 To 2
Sheet1.Cells(2, x).Resize(, UBound(Urn) - 1) = Application.WorksheetFunction.Transpose(.Range("E2:E" & UBound(Urn)).Value)
If i = 1 Then colwidth = 8.3 Else colwidth = 55
Sheet1.Cells(2, x).Resize(, UBound(Urn) - 1).ColumnWidth = colwidth
If x = 2 Then Sheet1.Cells(1, x) = "URN" Else Sheet1.Cells(1, x) = "XXXXX"
Sheet1.Cells(1, x).Resize(, UBound(Urn) - 1).MergeCells = True
Sheet1.Cells(1, x).Resize(, UBound(Urn) - 1).Interior.ColorIndex = 15
x = x + UBound(Urn) - 1
Next i
.Columns(5).Clear
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
If .Range("B" & i) <> "" Then
Dat = .Range("A" & i): Num = .Range("B" & i): Loc = .Range("C" & i)
With Sheet1
.Range("B3").Resize(lr, UBound(Urn) - 1).Font.Name = "Wingdings 2"
lc = .Cells(2, .Columns.Count).End(xlToLeft).Column
Set FndDt = .Range("A:A").Find(Dat, LookIn:=xlValues, lookat:=xlWhole)
Set FndNum = .Range(.Cells(2, 1), .Cells(2, lc)).Find(Num, LookIn:=xlValues, lookat:=xlWhole)
.Cells(FndDt.Row, FndNum.Column) = "P": .Cells(FndDt.Row, FndNum.Column).Font.Color = vbGreen
On Error Resume Next
If Not .Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) Like "*" & Loc & "*" Then
.Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) = IIf(.Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) = "", Loc, .Cells(FndDt.Row, FndNum.Column + UBound(Urn) - 1) & "," & Loc)
End If
End With
End If
Next i
With Sheet1
With .Range("B3").Resize(UBound(Dt) - 1, UBound(Urn) - 1)
.SpecialCells(xlCellTypeBlanks).Font.Color = vbRed: .SpecialCells(xlCellTypeBlanks).Value = "O":
End With
With .Range("B3").Offset(, UBound(Urn) - 1).Resize(UBound(Urn) - 1, UBound(Urn) - 1)
.SpecialCells(xlCellTypeBlanks).Interior.ColorIndex = 15
End With
AddOutsideBorders .Range("A1").Resize(UBound(Dt) + 1, 1 + ((UBound(Urn) - 1) * 2))
With .Cells
.Columns.AutoFit
.HorizontalAlignment = xlCenter
.RowHeight = 25
End With
End With
End With
Application.ScreenUpdating = True
End Sub
Public Function AddOutsideBorders(rng As Range)
With rng.Borders
.LineStyle = xlContinuous
.Color = vbBlack
.Weight = xlThin
End With
End Function
Related
So i have this userform that allows the user to key in the number of creditors and the number of rows for the table, then after the user clicks confirm, it will generate based on the input values
And now I need this details like which cell contains creditor name 1 and which range is creditor name 1 table like this picture below:
My current code is
'Clears Sheet then generates Number of Creditors & Rows
Worksheets("Payable Conf - by Invoice").Cells.Clear
Dim CreditorsCount As Integer
Dim Counter As Integer
Dim Rows As Integer
If TextBox1.Text <> "" And TextBox2.Text <> "" Then
CreditorsCount = TextBox1.Value
Counter = 0
CreditorsCount2 = 0
Rows = TextBox2.Value
End If
Worksheets("Payable Conf - by Invoice").Activate
While Counter < CreditorsCount
Cells((Counter * (5 + Rows) + 1), 1).Activate
With Range(ActiveCell.Address, ActiveCell.Offset(0, 4))
.Value = Array("Creditor Name " & CStr(Counter + 1), "Creditor Address 1", "Creditor Address 2", "Creditor Address 3", "Staff Email (e.g. abc123#gmail.com)")
.Font.Bold = True
End With
With Range(ActiveCell.Offset(3, 0), ActiveCell.Offset(3, 2))
.Value = Array("Invoice No.", "Invoice Date", "Amount (e.g. $100)")
.Font.Bold = True
End With
With Union(Range(ActiveCell.Address, ActiveCell.Offset(1, 4)), Range(ActiveCell.Offset(3, 0), ActiveCell.Offset(3 + Rows, 2)))
.BorderAround XlLineStyle.xlContinuous, xlThin
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
End With
Counter = Counter + 1
Wend
Worksheets("Payable Conf - by Invoice").Range("I8") = "Please do not edit"
Worksheets("Payable Conf - by Invoice").Range("I9") = "Number of Creditors:"
Worksheets("Payable Conf - by Invoice").Range("J9") = TextBox1.Value
Worksheets("Payable Conf - by Invoice").Range("I10") = "Number of Rows:"
Worksheets("Payable Conf - by Invoice").Range("J10") = TextBox2.Value
Help is greatly appreciated :)
Maybe something like this ?
Sub test()
Dim rg1 As Range
Dim rg2 As Range
Dim cnt As Integer
Dim TotRow As Integer
Dim tbl As Range
cnt = 5
TotRow = 10
With Sheets("Payable Conf - by Invoice")
'.Activate
.Cells.Delete
Set rg1 = .Range("A1")
Set rg2 = .Range("i8")
End With
With rg2
.Resize(3, 1).Value = Application.Transpose(Array("do not edit", "num cred", "num rows"))
.Offset(1, 1).Value = cnt
.Offset(2, 1).Value = TotRow
Set rg2 = rg2.Offset(4, 0)
End With
For i = 1 To cnt
With rg1.Resize(1, 5)
.Value = Array("cr name " & CStr(i), "add1", "add2", "add3", "email")
.Font.Bold = True
.Resize(2, 5).Borders.LineStyle = xlContinuous
End With
Set rg1 = rg1.Offset(3, 0)
With rg1.Resize(1, 3)
.Value = Array("Inv No", "Inv Date", "Inv Amount")
.Font.Bold = True
Set tbl = .Resize(TotRow + 1, 3)
tbl.Borders.LineStyle = xlContinuous
End With
With rg2
.Offset(0, 0).Value = "cred name " & CStr(i) & ":"
.Offset(0, 1).Value = rg1.Offset(-2, 0).Address(0, 0)
.Offset(1, 0).Value = "tbl " & CStr(i) & ":"
.Offset(1, 1).Value = tbl.Address(0, 0)
End With
Set rg1 = rg1.Offset(TotRow + 2, 0)
Set rg2 = rg2.Offset(3, 0)
Next i
End Sub
Please try to run the sub on a new workbook.
If the result is the one that you expected, just change the cnt variable value and the TotRow variable value to your TextBox1.value and TextBox2.value
I'm trying to sum the results of a loop. So far the code takes values from WsIn by row, runs them through a model and gives results in WsOut. The code takes the values in row 1 and gives results based on these and goes back and does it for row 2 and so on. The results are overwritten by the new results as the code loops. But I want it to add the results given by row 1 to the results given by row 2 added to row 3, etc. The results are ranges C5:C33 and D5:D33 in WsOut. I think the code for this would be something like the loop I put at the bottom but I'm not sure how to make this. Any ideas on what I should do?
Sub TEST1()
Dim WsIn As Worksheet ' Input
Dim WsT As Worksheet ' Taken
Dim WsOut As Worksheet ' Output
Dim WsMod As Worksheet ' Model
Dim Arr As Variant
Dim Rl As Long
Dim R As Long
Dim Rout As Long ' WsOut row
Dim Cmod As Long ' WsMod column
Dim XXX As Integer
Dim YYY As Integer
Dim WWW As Integer
Set WsT = Sheets("Inputs Taken")
Set WsIn = Sheets("Input Values")
Set WsOut = Sheets("Output")
Set WsMod = Sheets("Model")
Application.ScreenUpdating = False
Rl = WsIn.Cells(WsIn.Rows.Count, "B").End(xlUp).Row
For R = 2 To Rl
'Pasting Input Values into Inputs Taken
With WsIn
Arr = .Range(.Cells(R, 1), .Cells(R, 4)).Value
WsT.Cells(5, "D").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
Arr = .Range(.Cells(R, 5), .Cells(R, 6)).Value
WsT.Cells(11, "C").Resize(UBound(Arr), UBound(Arr, 2)).Value = Arr
Arr = .Range(.Cells(R, 7), .Cells(R, 8)).Value
WsT.Cells(16, "C").Resize(UBound(Arr), UBound(Arr, 2)).Value = Arr
Arr = .Range(.Cells(R, 9), .Cells(R, 14)).Value
WsT.Cells(9, "G").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
Arr = .Range(.Cells(R, 15), .Cells(R, 16)).Value
WsT.Cells(20, "C").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
Arr = .Range(.Cells(R, 17), .Cells(R, 18)).Value
WsT.Cells(20, "D").Resize(UBound(Arr, 2), UBound(Arr)) _
.Value = Application.Transpose(Arr)
End With
'Setting Opening PUP to 100% and refreshing
WsT.Cells(5, "G").Value = 1
Application.CalculateFull
'Calculating No RPs
With WsOut
Cmod = 62 ' BJ:BP
For Rout = 7 To 13
.Cells(Rout, "C").Value = SumProduct(Cmod, WsMod)
Cmod = Cmod + 1
Next Rout
.Cells(14, 3).Value = Application.Sum(.Range("C11:C13"))
Cmod = 71 ' BS:CB
For Rout = 17 To 26
.Cells(Rout, "C").Value = SumProduct(Cmod, WsMod, True)
Cmod = Cmod + 1
Next Rout
.Cells(5, 3).Value = WsMod.Cells(6, "BL").Value _
- WsMod.Cells(6, "BS").Value _
- WsMod.Cells(6, "BT").Value
.Cells(15, 3).Value = Application.Sum(.Range("C5,C7:C10, C14"))
.Cells(27, 3).Value = Application.Sum(.Range("C17:C26"))
.Cells(29, 3).Value = Application.Sum(WsMod.Range("AN6:AN365"))
.Cells(30, 3).Value = Application.Sum(WsMod.Range("AP6:AP365"))
.Cells(31, 3).Value = WsOut.Cells(2, 3).Value
.Cells(33, 3).Value = WsOut.Cells(15, 3) - Application.Sum(.Range("C29:C31, C27"))
End With
'Changing PUP rate
WsT.Cells(5, "G").Value = 0
Application.CalculateFull
'Calculate with RP
With WsOut
Cmod = 62 ' BJ:BP
For Rout = 7 To 13
.Cells(Rout, "D").Value = SumProduct(Cmod, WsMod)
Cmod = Cmod + 1
Next Rout
.Cells(14, 4).Value = Application.Sum(.Range("D11:D13"))
Cmod = 71 ' BS:CB
For Rout = 17 To 26
.Cells(Rout, "D").Value = SumProduct(Cmod, WsMod, True)
Cmod = Cmod + 1
Next Rout
.Cells(5, 4).Value = WsMod.Cells(6, "BL").Value _
- WsMod.Cells(6, "BS").Value _
- WsMod.Cells(6, "BT").Value
.Cells(15, 4).Value = Application.Sum(.Range("D5,D7:D10, D14"))
.Cells(27, 4).Value = Application.Sum(.Range("D17:D26"))
.Cells(29, 4).Value = Application.Sum(WsMod.Range("AN6:AN365"))
.Cells(30, 4).Value = Application.Sum(WsMod.Range("AP6:AP365"))
.Cells(31, 4).Value = WsOut.Cells(2, 3).Value
.Cells(33, 4).Value = WsOut.Cells(15, 4) - Application.Sum(.Range("D29:D31, D27"))
End With
'Exit For
Next R
Application.ScreenUpdating = True
For XXX = 5 To 33
For YYY = 6 To 7
For WWW = 3 To 4
WsOut.Cells(XXX, YYY).Value = WsOut.Cells(XXX, WWW).Value
Next WWW
Next YYY
Next XXX
End Sub
Private Function SumProduct(ByVal Cmod As Long, _
WsMod As Worksheet, _
Optional ByVal Negative As Boolean) As Double
Dim AuxRng As Range
With WsMod
Set AuxRng = .Range(.Cells(6, Cmod), .Cells(365, Cmod))
SumProduct = Application.SumProduct( _
.Range("AD6:AD365"), _
.Range("AG6:AG365"), _
AuxRng)
End With
End Function
Have an integer add to itself at the end of each loop. totNum = totNum + this rows count. At the end total sum will = totNum.
I have some problems with excel and VBA, in that don't know have much knowledge. I copied text from pdf and it's awful.
I have cells which contain some text.
The problem is that the text from one paragraph is broken down over several cells. At the beginning of each paragraph is a word in bold (e.g. CLR.) which describes the rest of the text. As such, it defines where each paragraph should start. How I can merge these cells into one?
I see
I want
Sub MergeText()
Dim strMerged$, r&, j&, i&
r = 1
Do While True
If Cells(r, 1).Characters(1, 1).Font.Bold Then
strMerged = "": strMerged = Cells(r, 1)
r = r + 1
While (Not Cells(r, 1).Characters(1).Font.Bold) And Len(Cells(r, 1)) > 0
strMerged = strMerged & Cells(r, 1)
r = r + 1
Wend
i = i + 1: Cells(i, 2) = strMerged
Cells(i, 2).Characters(1, InStr(1, strMerged, ".", vbTextCompare)).Font.Bold = True
Else
Exit Do
End If
Loop
End Sub
Modify (if needed) and try:
Option Explicit
Sub test()
Dim LastRow As Long, i As Long, j As Long, Count As Long
Dim str As String
With ThisWorkbook.Worksheets("Sheet1") 'Change sheet name if needed
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = LastRow To 2 Step -1
If (UCase(Left(.Range("A" & i), 1)) <> Left(.Range("A" & i), 1)) And UCase(Left(.Range("A" & i - 1), 1)) = Left(.Range("A" & i - 1), 1) Then
Count = 0
For j = 1 To Len(.Range("A" & i - 1))
If .Range("A1").Characters(j, 1).Font.FontStyle = "Bold" Then
Count = Count + 1
Else
Exit For
End If
Next j
str = .Range("A" & i - 1).Value & " " & .Range("A" & i).Value
With .Range("A" & i - 1)
.Value = str
.Font.Bold = False
With .Characters(Start:=1, Length:=Count).Font
.FontStyle = "Bold"
End With
End With
.Rows(i).EntireRow.Delete
ElseIf (UCase(Left(.Range("A" & i), 1)) <> Left(.Range("A" & i), 1)) And UCase(Left(.Range("A" & i - 1), 1)) <> Left(.Range("A" & i - 1), 1) Then
str = .Range("A" & i - 1).Value & " " & .Range("A" & i).Value
With .Range("A" & i - 1)
.Value = str
.Font.Bold = False
End With
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub
I am setting up a new pricing schedule which reads selected information from a 'Register' tab, based on selected criteria, and copying this into a new tab. This data is formatted so it looks aesthetically pleasing.
I am finding formatting the code is slowing down the run speed significantly. If possible I would like to speed this up as I will be iterating this multiple times.
I hae sped the program up a reasonable amount. Initially it took 30s, whereas now it is about 10s.
I have followed information from this website as best as I can:
https://www.soa.org/News-and-Publications/Newsletters/Compact/2012/january/com-2012-iss42-roper.aspx
I feel there is still scope to improve more, though I am unsure how, and am reaching out to see if there is, or are, better ways to improve the code so it runs quicker.
Option Explicit
Sub create_pricing_schedule()
'define workbook variables
Dim Start_Time As Double, End_Time As Double
Dim file1 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim ws4 As Worksheet
Dim namedRange1 As Range
Dim namedRange2 As Range
Set file1 = ThisWorkbook
Set ws2 = file1.Worksheets("Pricing Schedule")
Set ws3 = file1.Worksheets("Control")
Set ws4 = file1.Worksheets("Register")
Set namedRange1 = file1.Names("Client_Register").RefersToRange
Set namedRange2 = file1.Names("Pricing_Range").RefersToRange
'define general variables
Dim i As Integer
Dim collect(1 To 500, 1 To 10) As Variant
Dim rw As Range
Dim selectedClient As String
Dim lastrow As Integer, lastrow2 As Integer, lastrow3 As Integer
i = 1
'time how long it takes to improve efficiency
Start_Time = Timer
'speedup so less lagg
Call speedup
'delete everything from the pricing schedule/reset
With Sheets("Pricing Schedule")
.UsedRange.ClearContents
.Cells.Interior.ColorIndex = 0
.Cells.Borders.LineStyle = xlNone
.Cells.HorizontalAlignment = xlLeft
.Cells.MergeCells = False
.Range("A:Z").WrapText = False
.Rows.RowHeight = "15"
End With
'resize the client register
lastrow = ws4.Range("A100000").End(xlUp).Row
With ActiveWorkbook.Names("Client_Register")
.RefersTo = "=Register!$A$1:$AE$" & lastrow
End With
selectedClient = ws3.Range("B3").Value
'copy from database to the pricing schedule as a non formatted list of all the info - this runs quickly, but I am open to changing it
For Each rw In Range("Client_Register").Rows
If Range("Client_Register").Cells(rw.Row, 2) = selectedClient Then
collect(i, 1) = Range("Client_Register").Range("E" & rw.Row)
collect(i, 2) = Range("Client_Register").Range("D" & rw.Row)
collect(i, 3) = Range("Client_Register").Range("F" & rw.Row)
collect(i, 4) = Range("Client_Register").Range("J" & rw.Row)
collect(i, 5) = Range("Client_Register").Range("K" & rw.Row)
collect(i, 6) = Range("Client_Register").Range("L" & rw.Row)
collect(i, 7) = Range("Client_Register").Range("M" & rw.Row)
collect(i, 8) = Range("Client_Register").Range("P" & rw.Row)
collect(i, 9) = Range("Client_Register").Range("I" & rw.Row)
collect(i, 10) = Range("Client_Register").Range("H" & rw.Row) ' used to determine if pass through fee
ws2.Range("B" & i + 6) = collect(i, 1)
ws2.Range("C" & i + 6) = collect(i, 2)
ws2.Range("D" & i + 6) = collect(i, 3)
ws2.Range("E" & i + 6) = collect(i, 4)
ws2.Range("F" & i + 6) = collect(i, 5)
ws2.Range("G" & i + 6) = collect(i, 6)
ws2.Range("H" & i + 6) = collect(i, 7)
ws2.Range("I" & i + 6) = collect(i, 8)
ws2.Range("J" & i + 6) = collect(i, 9)
ws2.Range("K" & i + 6) = collect(i, 10)
i = i + 1
End If
Next
'add in the colour and count how many rows there are
lastrow2 = ws2.Range("C5000").End(xlUp).Row
With ActiveWorkbook.Names("Pricing_Range")
.RefersTo = "='Pricing Schedule'!$A$1:$K$" & lastrow2
End With
ws2.Range("B7" & ":" & "J" & lastrow2).Interior.Color = RGB(242, 242, 242)
'==========this bit is slow, can it be quicker?==========
'add spacing, titles, and colour to sub headers
i = 7
For Each rw In Range("Pricing_Range").Rows
If Range("Pricing_Range").Cells(i, 3) <> Range("Pricing_Range").Cells(i + 1, 3) Then
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Interior.ColorIndex = 0
Range("Pricing_Range").Rows(i + 2).Interior.ColorIndex = 0
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Interior.Color = RGB(255, 128, 1)
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Borders(xlEdgeTop).Color = RGB(0, 0, 0)
Range("Pricing_Range").Range("B" & i + 2 & ":" & "J" & i + 2).Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
Range("Pricing_Range").Range("B" & i + 2).Value = Range("Pricing_Range").Range("C" & i + 3).Value
'if it is a pass through fee then add it in to the sub headers
If Range("Pricing_Range").Range("K" & i + 3).Value = "Pass-Through" Then
Range("Pricing_Range").Range("J" & i + 2).Value = "Pass-Through Fees"
Range("Pricing_Range").Range("J" & i + 2).HorizontalAlignment = xlRight
End If
i = i + 3
Else
i = i + 1
End If
Next
'==================================================
'set up the main title rows
ws2.Select
Range("Pricing_Range").Range("B2").Value = ws3.Range("B3").Value
Range("Pricing_Range").Range("B2").Font.Size = 20
Range("Pricing_Range").Range("B2").Font.Bold = True
Range("Pricing_Range").Range("B2").Font.FontStyle = "Calibri Light"
Range("Pricing_Range").Range("B2:J3").Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.MergeCells = True
.Cells.Interior.Color = RGB(255, 128, 1)
.Cells.Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Cells.Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
End With
'tidy up things in the sheet
With Worksheets("Pricing Schedule")
'set up the headers and first title
.Range("B6") = .Range("C7")
.Range("B5:J6").Interior.Color = RGB(255, 128, 1)
.Range("B5:J5").Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Range("B5:J5").Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Range("B6:J6").Borders(xlEdgeTop).Color = RGB(0, 0, 0)
.Range("B6:J6").Borders(xlEdgeBottom).Color = RGB(0, 0, 0)
.Range("B5").Value = "Fee Code"
.Range("C5").Value = "Product Line"
.Range("D5").Value = "Item"
.Range("E5").Value = "Volume From"
.Range("F5").Value = "Volume To"
.Range("G5").Value = "Frequency"
.Range("H5").Value = "Location"
.Range("I5").Value = "Price"
.Range("J5").Value = "Nature of Fee"
'tidy up column widths
.Range("A5").RowHeight = 30
.Range("A1").ColumnWidth = 2
.Range("B1").ColumnWidth = 15
.Range("C1").ColumnWidth = 40
.Range("D1").ColumnWidth = 45
.Range("E1").ColumnWidth = 11
.Range("F1").ColumnWidth = 11
.Range("G1").ColumnWidth = 35
.Range("H1").ColumnWidth = 15
.Range("I1").ColumnWidth = 12
.Range("J1").ColumnWidth = 50
.Range("J:J").WrapText = True
.Range("K:K").Delete
End With
'clear the extra orange line at the end
lastrow3 = ws2.Range("B1000").End(xlUp).Row
With ws2.Rows(lastrow3 + 2)
.Cells.Interior.ColorIndex = 0
.Cells.Borders.LineStyle = xlNone
.ClearContents
End With
'add print area
With Worksheets("Pricing Schedule")
.PageSetup.Zoom = False
.PageSetup.Orientation = xlPortrait
.PageSetup.PrintArea = "$B$2:$J$" & lastrow3
.PageSetup.FitToPagesWide = 1
.PageSetup.FitToPagesTall = False
.PageSetup.PrintTitleRows = "$2:$6"
End With
'return to normal
Call slowdown
'time how long it takes to improve efficiency
End_Time = Timer
Worksheets("Control").Cells(6, 2) = End_Time - Start_Time
End Sub
Sub speedup()
Application.Calculation = xlManual
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayStatusBar = False
End Sub
Sub slowdown()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayStatusBar = True
End Sub
I found a few lines that could save you some execution time.
'****EDIT****Changed this to direct range reference rather than go through the Names collection.
'Set namedRange1 = file1.Names("Client_Register").RefersToRange
'Set namedRange2 = file1.Names("Pricing_Range").RefersToRange
Set namedRange1 = file1.Range("Client_Register")
Set namedRange2 = file1.Range("Pricing_Range")
Used range takes more time rather use .cells directly
'delete everything from the pricing schedule/reset
'****EDIT***
With ws2 'Sheets("Pricing Schedule")
'used range takes more time rather use .cells directly
.Cells.ClearContents
Rather than use arrays you can directly update values as shown below
'I am using i for the row count
ws2.Range("B" & i + 6).Value = namedRange1.Cells(i, 5).Value
ws2.Range("C" & i + 6).Value = namedRange1.Cells(i, 4).Value
ws2.Range("D" & i + 6).Value = namedRange1.Cells(i, 6).Value
ws2.Range("E" & i + 6).Value = namedRange1.Cells(i, 10).Value
ws2.Range("F" & i + 6).Value = namedRange1.Cells(i, 11).Value
ws2.Range("G" & i + 6).Value = namedRange1.Cells(i, 12).Value
ws2.Range("H" & i + 6).Value = namedRange1.Cells(i, 12).Value
ws2.Range("I" & i + 6).Value = namedRange1.Cells(i, 16).Value
ws2.Range("J" & i + 6).Value = namedRange1.Cells(i, 9).Value
ws2.Range("K" & i + 6).Value = namedRange1.Cells(i, 8).Value
i = i + 1
The main culprit for your slower performance is the insert operation. try to work the logic to not having insert. If not possible, try to insert rows outside the loop in a single operation rather than in the loop
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Range("Pricing_Range").Rows(i + 1).Insert Shift:=xlShiftDown
Your handling of the collect array is inefficient. Consider reading the entire Client Register into an array with MyArray = Range.Value. Then prepare the output array in memory and write it to the worksheet after all looping is done, in one go, with TargetRange.Value = collect.
Avoid inserting rows. What's wrong with the existing? If you are preparing all data in an array to be pasted to the worksheet, empty array elements will produce empty worksheet cells. In this way all inserting can be avoided and all you need to do is to format.
There is time cost for every access to the worksheet, whether to read or write. Even for formatting, try to create ranges that are treated in the same manner. Avoid accessing the worksheet in loops.
Example of With and block assignment from an array:
'copy from database to the pricing schedule as a
' non formatted list of all the info - this runs quickly,
' but I am open to changing it
With Range("Client_Register")
For Each rw In .Rows
If .Cells(rw.Row, 2) = selectedClient Then
collect(i, 1) = .Range("E" & rw.Row)
collect(i, 2) = .Range("D" & rw.Row)
collect(i, 3) = .Range("F" & rw.Row)
collect(i, 4) = .Range("J" & rw.Row)
collect(i, 5) = .Range("K" & rw.Row)
collect(i, 6) = .Range("L" & rw.Row)
collect(i, 7) = .Range("M" & rw.Row)
collect(i, 8) = .Range("P" & rw.Row)
collect(i, 9) = .Range("I" & rw.Row)
collect(i, 10) = .Range("H" & rw.Row)
'you could even skip the row-by-row population of values
' and assign as a block after exiting the loop
ws2.Range("B" & i + 6).Resize(1, 10).Value = _
Array(collect(i, 1), collect(i, 2), collect(i, 3), _
collect(i, 4), collect(i, 5), collect(i, 6), _
collect(i, 7), collect(i, 8), collect(i, 9), _
collect(i, 10))
i = i + 1
End If
Next
End With
Note this will break if your Client_Register refers to a range which doesn't start on Row1, because of the relative range references.
Eg:
Range("A1:A10").Range("A1") 'refers to A1
Range("A2:A10").Range("A1") 'refers to A2
How can I separate time from time zone and put time in format "yyyy-m hh:mm:ss". Lookin for the column “Time”, create other two columns: “Time*” and “Time_Zone” .
I adapted this code, but some error occur and I put “On Error Resume Next”
For Each ws In Worksheets
For i = 1 To ws.Columns.Count
If ws.Cells(1, i) = "Hour" Then
Set s = ws.Cells(1, i)
LC = s.Column
ws.Columns(LC + 1).Insert
ws.Columns(LC).Copy
ws.Cells(1, LC + 1).PasteSpecial Paste:=xlPasteValues
ws.Cells(1, LC + 1).Value = "Time*"
Exit For
End If
Next i
For i = 1 To ws.Columns.Count
If ws.Cells(1, i) = "Time*" Then
ColLetr = Split(Cells(1, i).Address, "$")(1)
y = i
Exit For
End If
Next i
If ColLetr <> "" Then
lastRow = ws.Cells(Rows.Count, y).End(xlUp).Row
For Each cell In ws.Range(ColLetr & "3:" & ColLetr & lastRow)
If InStr(cell.Value, "/") <> 0 Then
cell.Value = RegexReplace(cell.Value, _
"(\d{2})\/(\d{2})\/(\d{4})", "$3-$2-$1")
End If
cell.NumberFormat = "yyyy-mm-dd hh:mm:ss;#"
If cell.Value <> "" Then
cell.Value = Left(cell.Value, 19)
End If
Next
End If
For i = 1 To ws.Columns.Count
If ws.Cells(1, i) = "Hour" Then
Set s = ws.Cells(1, i)
LC = s.Column
ws.Columns(LC + 2).Insert
ws.Columns(LC).Copy
ws.Cells(1, LC + 2).PasteSpecial Paste:=xlPasteValues
ws.Cells(1, LC + 2).Value = "Time_Zone"
Exit For
End If
Next i
For i = 1 To ws.Columns.Count
If ws.Cells(1, i) = "Time_Zone" Then
ColLetr = Split(Cells(1, i).Address, "$")(1)
y = i
Exit For
End If
Next i
If ColLetr <> "" Then
lastRow = ws.Cells(Rows.Count, y).End(xlUp).Row
For Each c In ws.Range(ColLetr & "3:" & ColLetr & lastRow)
If c.Value <> "" Then
On Error Resume Next
c.Value = Right(c.Value, Len(c.Value) - 20)
End If
Next
End If
Next
Application.ScreenUpdating = False
End Sub
Function RegexReplace(ByVal text As String, _
ByVal replace_what As String, _
ByVal replace_with As String) As String
Application.ScreenUpdating = False
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = replace_what
RE.Global = True
RegexReplace = RE.Replace(text, replace_with)
Application.ScreenUpdating = True
End Function
This code works for me:
Sub test()
Dim ws As Worksheet
Dim rngTime As Range
Dim cell As Range
Dim rngTarget As Range
Dim formatedTime As String
Application.ScreenUpdating = False
For Each ws In Worksheets
With ws
Set rngTime = .Range("1:1").Find(What:="Time", MatchCase:=False, LookAt:=xlWhole)
If Not rngTime Is Nothing Then
rngTime.Offset(, 1).Resize(, 2).EntireColumn.Insert
rngTime.Offset(, 1) = "Time*"
rngTime.Offset(, 2) = "Time_Zone"
lastrow = .Cells(.Rows.Count, rngTime.Column).End(xlUp).Row
Set rngTarget = .Range(.Cells(3, rngTime.Column + 1), .Cells(lastrow, rngTime.Column + 1))
rngTarget.NumberFormat = "yyyy-mm-dd hh:mm:ss;#"
For Each cell In rngTarget
If InStr(cell.Offset(, -1), "/") <> 0 Then
formatedTime = RegexReplace(cell.Offset(, -1), _
"(\d{2})\/(\d{2})\/(\d{4})", "$3-$2-$1")
cell = Trim(Left(formatedTime, 19))
cell.Offset(, 1) = Trim(Mid(formatedTime, 20))
End If
Next cell
End If
End With
Next ws
Application.ScreenUpdating = True
End Sub
Function RegexReplace(ByVal text As String, _
ByVal replace_what As String, _
ByVal replace_with As String) As String
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
RE.Pattern = replace_what
RE.Global = True
RegexReplace = RE.Replace(text, replace_with)
End Function
Note, that in your picture you're using Time header in column E, but in your're searching Hour column: If ws.Cells(1, i) = "Hour" Then. I use Time header in my code, you could change it in line Set rngTime = .Range("1:1").Find(What:="Time", MatchCase:=False, LookAt:=xlWhole).
Result: