How to speed up this looping code? - excel

Can you anyone offer assistance on speeding up this code? I am assume an array can be used, but I am terrible using them. Is there another way? Thanks so much!
Application.ScreenUpdating = False
'IF using Indexed Values
If Sheets("interface").Range("C24") = "Y" Then
Dim x As Integer
Dim i As Long
For x = 15 To 51
LastRow = Sheets("db_main").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If Sheets("db_main").Range("S" & i) = True And Sheets("db_main").Range("C" & i) = Sheets("interface").Range("F" & x) Then
Sheets("db_main").Range("C" & i).Copy
Sheets("intersource").Range("A" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("db_main").Range("A" & i).Copy
Sheets("intersource").Range("B" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("db_main").Range("H" & i).Copy
Sheets("intersource").Range("C" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("db_main").Range("D" & i).Copy
Sheets("intersource").Range("D" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("db_main").Range("M" & i).Copy
Sheets("intersource").Range("E" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
Sheets("db_main").Range("O" & i).Copy
Sheets("intersource").Range("F" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial Paste:=xlPasteValues
End If
Next i
Next x
End If

If you'd like to avoid using arrays, you could try eliminating the copy/paste in favor of just assigning values (which should improve the performance). Try this out:
'IF using Indexed Values
Application.ScreenUpdating = False
If Sheets("interface").Range("C24") = "Y" Then
Dim x As Long, i As Long, LastRow As Long, _
LastSourceRow As Long, Counter As Long
Dim DBSheet As Worksheet, SourceSheet As Worksheet, _
InterSheet As Worksheet
'identify worksheets for easier reference
Set DBSheet = ThisWorkbook.Worksheets("db_main")
Set SourceSheet = ThisWorkbook.Worksheets("intersource")
Set InterSheet = ThisWorkbook.Worksheets("interface")
For x = 15 To 51
'identify last rows
LastRow = DBSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastSourceRow = SourceSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Counter = 1
For i = 2 To LastRow
If DBSheet.Range("S" & i) = True And DBSheet.Range("C" & i) = InterSheet.Range("F" & x) Then
'write DB column C to Source column A
SourceSheet.Cells(LastSourceRow + Counter, 1) = _
DBSheet.Cells(i, 3).Value
'write DB column A to Source column B
SourceSheet.Cells(LastSourceRow + Counter, 2) = _
DBSheet.Cells(i, 1).Value
'write DB column H to Source column C
SourceSheet.Cells(LastSourceRow + Counter, 3) = _
DBSheet.Cells(i, 8).Value
'write DB column D to source column D
SourceSheet.Cells(LastSourceRow + Counter, 4) = _
DBSheet.Cells(i, 4).Value
'write DB column M to Source column E
SourceSheet.Cells(LastSourceRow + Counter, 5) = _
DBSheet.Cells(i, 13).Value
'write DB column O to Source column F
SourceSheet.Cells(LastSourceRow + Counter, 6) = _
DBSheet.Cells(i, 15).Value
'increment counter
Counter = Counter + 1
End If
Next i
Next x
End If
Application.ScreenUpdating = True

Related

How to copy and paste data, in lots of 200, from horizontal to vertical?

I am trying to copy and paste data from horizontal to vertical from sheet1 to sheet3 in a lots of 200.
Say I have a list of 600 tickers. The code will copy the first 200 from sheet1 cells ("C6 till GT7") and paste it vertically in sheet3 cell A2.
I need the next lot of 200 appended in sheet3 after row 201.
My code is pasting only the last 200 in sheet 3.
Sub getbulkprices()
Application.ScreenUpdating = False
Dim wb As Workbook, ws, ws1 As Worksheet
Dim r, iLastRow As Long, plr as long
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set ws1 = wb.Sheets("Sheet2")
iLastRow = ThisWorkbook.Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Row
ThisWorkbook.Sheets("Sheet1").Range("A2:A500").ClearContents
ThisWorkbook.Sheets("Sheet3").Range("A2:B500000").ClearContents
For r = 2 To ws1.Range("A" & Rows.Count).End(xlUp).Row Step 200
ThisWorkbook.Sheets("Sheet1").Cells(2, 1).Resize(200).Value = _
ws1.Cells(r, 1).Resize(200).Value
ws.Range("C1").FormulaR1C1 = "=#RHistory(R2C1:R200C1,"".Timestamp;.Close"",""NBROWS:""&R2C2&"" INTERVAL:1D"",,""SORT:ASC TSREPEAT:NO CH:In;"",R[5]C)"
Application.Run "EikonRefreshWorksheet"
Application.Wait (Now + TimeValue("0:00:02"))
plr = ThisWorkbook.Sheets("Sheet3").Cells(Rows.Count, 1).End(xlUp).Row
ws.Range("D6:IK7").Copy
ThisWorkbook.Sheets("Sheet3").Range("A2:B" & plr + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=True
Application.CutCopyMode = False
Application.StatusBar = r & " / " & iLastRow - 1
Next r
End Sub
Consider qualifying the Rows.Count to the that same worksheet as qualifier to .Cells in the plr assignment:
plr = ThisWorkbook.Sheets("Sheet3").Cells( _
ThisWorkbook.Sheets("Sheet3").Rows.Count, 1 _
).End(xlUp).Row
Even better situate the copy and paste inside a With block to avoid repetition of worksheet:
For r = 2 To ... Step 200
...
With ThisWorkbook.Sheets("Sheet3")
plr = .Cells(.Rows.Count, 1).End(xlUp).Row
ws.Range("D6:IK7").Copy
.Range(.Cells(plr + 1, 1), _
.Cells(plr + 200, 2) _
).PasteSpecial _
Paste:=xlPasteValues, _
Operation:=xlNone, _
SkipBlanks:=False, _
Transpose:=True
End With
...
Next r
Consider even WorksheetFunction.Transpose and avoid copy/paste:
With ThisWorkbook.Sheets("Sheet3")
plr = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range(.Cells(plr + 1, 1), _
.Cells(plr + 200, 2) _
) = WorksheetFunction.Transpose(ws.Range("D6:IK7"))
End With
Change the paste to
ThisWorkbook.Sheets("sheet3").Range("A" & plr + 1 & ":B" & plr + 201).PasteSpecial...

Reducing size of a macro

Our company has 36 departments and we use a master budgeting worksheet to develop the budget. The department numbers are not sequential and their budgets are all different. I put together the following macro to send the worksheets to the individual departments. The master is full of VLOOKUPs and other formulae, but the individual departments receive only the final results and a couple of columns for their changes. They can make changes to any number that is not highlighted in yellow. The macro works perfectly for only one department, but when I tried to copy it 35 times below itself so that I could send a worksheet to all departments, I received an error message that said my procedure was too large. I divided it in half and I still received the message!
Sub Macro1()
'
' Macro1 Macro
'' Prepares O&M budget Worksheet for uploading
' Dim sourceSheet as Worksheet
Workbooks.Open Filename:="F:\Rick\2020 Budget\2020 O&M Budget.xlsx"
Set sourcesheet = Worksheets("Dept Detail-O&M Book")
sourcesheet.Activate
' Dim N As Long
' Dim T As Long
' Dim LastRow As Long
lastrow = Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp).Row
Dim i As Long, Total As Long
Dim cell As Range
Application.EnableEvents = False
'
Application.Goto Reference:="Dept_01"
Selection.Copy
Workbooks.Open Filename:="Q:\O&M\Departmental Budgets\Dept 1 MOEC.xlsx"
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:= _
xlNone, SkipBlanks:=False, Transpose:=False
ThisWorkbook.Activate
Application.CutCopyMode = False
Selection.Copy
Windows("Dept 1 MOEC.xlsx").Activate
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
Range("R1").Select
Selection.End(xlDown).Select
Selection.End(xlDown).Select
Selection.End(xlDown).Select
Selection.End(xlDown).Select
Application.CutCopyMode = False
n = Cells(Rows.Count, "R").End(xlUp).Row
Cells(n, "R").Formula = "=SUM(R1:R" & n - 1 & ")"
activecell.Select
Selection.Copy
activecell.Offset(0, 2).Select
ActiveSheet.Paste
Selection.Copy
activecell.Offset(0, 2).Select
ActiveSheet.Paste
Range("X9").Select
activecell.FormulaR1C1 = "=iferror(+RC[-2]/RC[-10],0)"
Range("X9").Select
T = Cells(Rows.Count, "X").End(xlUp).Row
Selection.AutoFill Destination:=Range("x9:x" & T)
With ActiveSheet
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
Application.EnableEvents = False
For i = lastrow To 1 Step -1
If Range("B" & i).Value = "1010" Or _
Range("B" & i).Value = "1020" Or _
Range("B" & i).Value = "2172" Or _
Range("B" & i).Value = "2190" Or _
Range("B" & i).Value = "2200" Or _
Range("B" & i).Value = "2290" Or _
Range("B" & i).Value = "4020" Or _
Range("B" & i).Value = "4050" Or _
Range("B" & i).Value = "4060" Or _
Range("B" & i).Value = "4070" Or _
Range("B" & i).Value = "4090" Or _
Range("B" & i).Value = "4100" Or _
Range("B" & i).Value = "4110" Or _
Range("B" & i).Value = "4509" Or _
Range("B" & i).Value = "4510" Or _
Range("B" & i).Value = "4600" Or _
Range("B" & i).Value = "4610" Or _
Range("B" & i).Value = "4700" Or _
Range("B" & i).Value = "5710" Or _
Range("B" & i).Value = "5721" Or _
Range("B" & i).Value = "5723" Or _
Range("B" & i).Value = "5725" Or _
Range("B" & i).Value = "5729" Or _
Range("B" & i).Value = "5730" Or _
Range("B" & i).Value = "5731" Then
.Range("R" & i).Interior.Color = RGB(255, 255, 0)
.Range("T" & i).Interior.Color = RGB(255, 255, 0)
End If
Next i
Application.EnableEvents = True
End With
With ActiveSheet
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
Application.EnableEvents = False
For i = lastrow To 1 Step -1
If Range("B" & i).Value = "5721" Or _
Range("B" & i).Value = "9000" Or _
Range("B" & i).Value = "9005" Or _
Range("B" & i).Value = "9010" Or _
Range("B" & i).Value = "9030" Then
.Range("R" & i).Interior.Color = RGB(255, 255, 0)
.Range("T" & i).Interior.Color = RGB(255, 255, 0)
End If
Next i
Application.EnableEvents = True
End With
Range("A1").Select
ActiveWorkbook.Save
ActiveWindow.Close
End Sub
Could someone offer suggestions on how to reduce the size of the macro and/or make it more efficient? Thanks!
I took a shot at cleaning this up (at least to make it run, for now) - I don't know enough about what you're doing to clean up that mid section, though. The problem undoubtedly was that long If statement.
Instead of all the Ors, put all your values in an array then test against that array with IsError:
Option Explicit
Sub Macro1()
Dim valuearr As Variant
Dim cell As Range
Dim sourcesheet As Worksheet
Dim lastrow As Long, i As Long, n As Long
Workbooks.Open Filename:="F:\Rick\2020 Budget\2020 O&M Budget.xlsx"
Set sourcesheet = Worksheets("Dept Detail-O&M Book")
sourcesheet.Activate
lastrow = Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp).Row
Application.EnableEvents = False
'This section needs to be cleaned up...
Application.Goto Reference:="Dept_01"
Selection.Copy
Workbooks.Open Filename:="Q:\O&M\Departmental Budgets\Dept 1 MOEC.xlsx"
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:= _
xlNone, SkipBlanks:=False, Transpose:=False
ThisWorkbook.Activate
Application.CutCopyMode = False
Selection.Copy
Windows("Dept 1 MOEC.xlsx").Activate
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
Range("R1").Select
Selection.End(xlDown).Select
Application.CutCopyMode = False
n = Cells(Rows.Count, "R").End(xlUp).Row
Cells(n, "R").Formula = "=SUM(R1:R" & n - 1 & ")"
ActiveCell.Copy
ActiveCell.Offset(0, 2).Paste
Selection.Offset(0, 2).Select
ActiveSheet.Paste
Range("X9").FormulaR1C1 = "=iferror(+RC[-2]/RC[-10],0)"
Range("X9").AutoFill Destination:=Range("x9:x" & Cells(Rows.Count, "X").End(xlUp).Row)
With ActiveSheet
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
valuearr = Array(1010, 1020, 2172, 2190, 2200, 2290, 4020, 4050, 4060, 4070, 4090, 4100, 4110, 4509, 4510, 4600, 4610, 4700, 5710, 5721, 5723, 5725, 5729, 5730, 5731, 9000, 9005, 9010, 9030)
For i = lastrow To 1 Step -1
If IsError(Application.Match(Range("B" & i).Value, valuearr, 0)) Then
.Range("R" & i).Interior.Color = RGB(255, 255, 0)
.Range("T" & i).Interior.Color = RGB(255, 255, 0)
End If
Next i
End With
Application.EnableEvents = True
ActiveWorkbook.Save
ActiveWindow.Close
End Sub

Appending data from one sheet to another Excel VBA

I know a bit of VBA, however I got a problem, I am trying to write a code that will copy all data from 1 sheet, append/paste it into the next blank cell in sheet 2 and then remove the data from sheet 1. I am using below code, but I get cell values replaced by the word TRUE.
Sub Instal_Sum_Paste()
ActiveWorkbook.Sheets("Vehicle working").Select
Dim N As Long
N = Cells(6, 2).End(xlDown).Row
Set DT = Range("b6:G" & N)
DT.Copy
ActiveWorkbook.Sheets("Installation Summary").Select
lMaxRows = Cells(Rows.Count, "B").End(xlUp).Row
Range("B" & lMaxRows + 1).Select
ActiveCell.Value = DT.PasteSpecial(xlPasteValues)
ActiveWorkbook.Sheets("Vehicle working").Select
DT.Select
Selection.ClearContents
MsgBox "done", vbOKOnly, "done"
End Sub
I managed to find an answer, its silly I know:
Sub Instal_Sum_Paste()
ActiveWorkbook.Sheets("Vehicle working").Select
Dim N As Long
N = Cells(6, 2).End(xlDown).Row
Set DT = Range("b6:G" & N)
DT.Select
Selection.Copy
ActiveWorkbook.Sheets("Installation Summary").Select
lMaxRows = Cells(Rows.Count, "B").End(xlUp).Row
Range("B" & lMaxRows + 1).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone
ActiveWorkbook.Sheets("Vehicle working").Select
DT.Select
Selection.ClearContents
MsgBox "done", vbOKOnly, "done"
End Sub

Comparing two range of cells A and D and copy the duplicate data

If A & D match, paste A into G. Then add B & E and place the results in column H. Im having the problem to add value from B & E into H.
Private Sub CommandButton1_Click()
Dim rng1 As Range
Dim rng2 As Range
Dim RowNo As Long
Dim LR As Long
Set rng1 = Worksheets("Sheet1").Range("D1:D100", Worksheets("Sheet1").Range("D" & Rows.Count).End(xlUp))
Set rng2 = Worksheets("Sheet1").Range("A1:A100", Worksheets("Sheet1").Range("A" & Rows.Count).End(xlUp))
For Each d In rng1
LR = Range("H" & Rows.Count).End(xlUp).Row
Range("F1:F" & LR).Formula = "=H1+C1"
If Not d.Value = "" And Application.WorksheetFunction.CountIf(rng2, d) > 0 Then
RowNo = Application.WorksheetFunction.Match(d, rng2)
If d.Offset(, 1).Value = "" Then d.Offset(, 3).Resize(1).Value _
= Worksheets("Sheet1").Range("A" & RowNo).Value
If d.Offset(, 1).Value = "" Then d.Offset(, 4).Resize(1).Value _
= Worksheets("Sheet1").Range("B" & RowNo).Value
End If
Next d
End Sub
Example cells:
A 1 X 22 A 45
B 2 C 33 C 36
C 3 A 44 F 105
D 4 Y 55
E 5 J 66
F 6 O 77
G 7 T 88
F 99
W 11
if the Problem is only to put the right numbers into H, use this code for that. Put it just be for "end Sub".
The code supposes you are never having more than 1000 rows filled in A and D, but you can change that.
Range("H1").Select
ActiveCell.FormulaR1C1 = _
"=SUMIF(R1C1:R1000C1,RC[-1],R1C2:R1000C2)+SUMIF(R1C4:R1000C4,RC[-1],R1C5:R1000C5)"
Selection.Copy
Range("H2:H" & WorksheetFunction.CountA(Columns(7))).Select
ActiveSheet.Paste
Application.CutCopyMode = False
Range("H1:H" & WorksheetFunction.CountA(Columns(7))).Select
'the following lines are only necessary if you don't want a formula in H.
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
hope that helps!
Max

VBA macro to group all rows under one heading, headings when more than one heading exists

I am writing a vba macro to achieve the following but do not how to implement it. Would any please provide some guidance?
Currently, the data is as follows(subitem spans from column B onwards):
ITEM ONE [Subitem one... ]
ITEM ONE [Subitem two ...]
ITEM ONE [Subitem three...]
ITEM TWO [Subitem one ...]
ITEM THREE [Subitem one...]
ITEM Three [Subitem two...]
The following is what the data should look like in a separate sheet:
ITEM ONE
--------
Subitem one
Subitem two
Subitem three
ITEM TWO
--------
Subitem one
ITEM THREE
----------
Subitem one
Subitem two
Any guidance/help will be greatly appreciated.
Edited: solution as follows:
r = Range("a65536").End(xlUp).Row
c = Range("IU1").End(xlToLeft).Column
a = Split(Cells(, c).Address, "$")(1)
MsgBox "last row with data is " & r & " and last column with data is " & a & "", vbOKOnly, "LastRow and LastCol"
rr = r + 1
Application.Visible = False
Range("A1:" & a & r & "").Sort Key1:=Range("B2"), Order1:=xlAscending, Header:= _
xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Sheets("owssvr(1)").Select
Sheets.Add
'by default select first record and paste in reports sheet
Sheets("owssvr(1)").Select
Range("b2").Select
Selection.Copy
Sheets(1).Select
Range("b2").Select
ActiveSheet.Paste
'paste header below it
Sheets("owssvr(1)").Select
Range("c1:" & a & "2").Select
Selection.Copy
Sheets(1).Select
Range("b3").Select
ActiveSheet.Paste
For i = 3 To r
Sheets(2).Select
'Program name is same as above, dont copy name but row starting from next col, switch to other sheet, find last row in col B, add one to last row and paste
If Cells(i, 2).Value = Cells(i - 1, 2) Then
Range("C" & i & ":" & a & i & "").Select
Selection.Copy
Sheets(1).Select
'Range("b3").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
Else
'if name is not same as above, copy name, find last row, add two to add a gap from prev program name, paste program name, move to next row and paste remaining cols
Sheets(2).Select
Range("B" & i & "").Select
Selection.Copy
Sheets(1).Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 2 & "").Select
ActiveSheet.Paste
'copy headers
Sheets(2).Select
Range("c1:" & a & "1").Select
Selection.Copy
Sheets(1).Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
'copy cells(row, col+1)
Sheets(2).Select
Range("C" & i & ":" & a & i & "").Select
Selection.Copy
Sheets(1).Select
'Range("b3").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
End If
Next
What you're asking for can be done with a PivotTable. I'm working in Excel 2010, but 2003 should probably have the same functionality. This is how it would look like.
The naive VBA approach I was going to do (which I guess you've implemented) was looping through all the items, doing comparisons, and adding them one at a time to the new worksheet. This can be made a bit more efficient if you store the initial range (of 2 columns) in an array, loop through that and store the output in a 2nd array, then copy the array back to a range.
I'm not sure how much data you have or how long that operation takes. Another alternative would be to use the macro recorder to make a PivotTable and copy the data from there to a new sheet. Here's an example, though you'd want to change the worksheet and range references to make them explicit/dynamic. The example data range is A1:B9.
Sub Example()
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Sheets.Add
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
"Sheet1!R1C1:R9C2", Version:=xlPivotTableVersion14).CreatePivotTable _
TableDestination:="Sheet4!R3C1", TableName:="PivotTable1", DefaultVersion _
:=xlPivotTableVersion14
Sheets("Sheet4").Select
Cells(3, 1).Select
With ActiveSheet.PivotTables("PivotTable1").PivotFields("item1")
.Orientation = xlRowField
.Position = 1
End With
With ActiveSheet.PivotTables("PivotTable1").PivotFields("sub12")
.Orientation = xlRowField
.Position = 2
End With
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets("Sheet2").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
your old worksheet is called yourWorksheet.
create a new worksheet:
set newWS = thisworkbook.workbooks.add()
dim rr as long
rr =1
for r = startRow to yourWorksheet.UsedRange.Rows.Count
firstItem = yourWorksheet.cells(r,1).value
newWS.cells(rr,1).value = firstItem
rr = rr + 1
do while firstItem = yourworksheet.cells(r,1).value
newWS.cells(rr,1).value = yourworksheet.cells(rr,2).value 'copy all columns here
rr = rr + 1
r =r + 1
loop
next r
rough and untested, but that's the idea.
If you use the left command and extract the Item One, Item Two, etc.
Heading(row) = Left(Cells(row,"B"), 8)
then extract the subItem:
SubItem(row) = Left(Right(cells(row, "B"), 20), 10)
These will extract the text.
You have to get creative for THREE and FOUR.
Sub Sort1()
'
' Sort1 Macro
' Macro recorded 7/30/2012 by American International Group
'
'
Dim r As Integer
Dim c As Integer
Dim lr2 As Integer
Dim a As String
Dim b As String
Dim cdb As Long
Dim name1 As String
Dim name2 As String
n1 = InputBox(Prompt:="Enter a name for worksheet else click OK", Title:="Enter a name for this sheet", Default:="owssvr")
n2 = InputBox(Prompt:="Enter a name for the Report view sheet else click OK", Title:="Enter a name for Report sheet", Default:="reportView")
b = InputBox(Prompt:="Enter Column Name on which to sort data", Title:="Sort by", Default:="B")
b = UCase(b) 'convert to uppercase e.g.c to C
asciiCol = Asc(b) 'convert to ascii 66
asciiNext = asciiCol + 1 'add one to ascii to get next column ascii code e.g. 66+1=67 to get D
sortbyColNo = 0
sortbyColNo = Range(b & "1").Column
'Rename sheets to avoid conflict
Sheets(1).name = n1
Sheets("" & n1 & "").Select
r = Range("a65536").End(xlUp).Row
c = Range("IU1").End(xlToLeft).Column
a = Split(Cells(, c).Address, "$")(1)
x = Split(Cells(, c).Address, "$")(2)
MsgBox "last row with data is " & r & " and last column with data is " & a & "", vbOKOnly, "LastRow and LastCol"
rr = r + 1
'Application.Visible = False
Range("A1:" & a & r & "").Sort Key1:=Range("" & b & "2"), Order1:=xlAscending, Header:= _
xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Sheets("" & n1 & "").Select
Sheets.Add
ActiveSheet.name = n2
'by default select first record and paste in reports sheet
Sheets("" & n1 & "").Select
Range("" & b & "2").Select
Selection.Copy
Sheets("" & n2 & "").Select
Range("b2").Select
ActiveSheet.Paste
'paste header below it
Sheets("" & n1 & "").Select
Range("" & Chr(asciiNext) & "1:" & a & "1").Select
With Selection
.Font.Bold = True
End With
Range("" & Chr(asciiNext) & "1:" & a & "2").Select
Selection.Copy
Sheets("" & n2 & "").Select
Range("b3").Select
ActiveSheet.Paste
'start from row 3
For i = 3 To r
Sheets("" & n1 & "").Select
'Program name is same as above, dont copy name but row starting from next col, switch to other sheet, find last row in col B, add one to last row and paste
If Cells(i, sortbyColNo).Value = Cells(i - 1, sortbyColNo) Then
Range("" & Chr(asciiNext) & "" & i & ":" & a & i & "").Select
Selection.Copy
Sheets("" & n2 & "").Select
'Range("b3").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
Else
'if name is not same as above, copy name, find last row, add two to add a gap from prev program name, paste program name, move to next row and paste remaining cols
Sheets("" & n1 & "").Select
Range("" & b & "" & i & "").Select
Selection.Copy
Sheets("" & n2 & "").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 2 & "").Select
ActiveSheet.Paste
'copy headers
Sheets("" & n1 & "").Select
Range("" & Chr(asciiNext) & "1:" & a & "1").Select
Selection.Copy
Sheets("" & n2 & "").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
'copy cells(row, col+1)
Sheets("" & n1 & "").Select
Range("" & Chr(asciiNext) & i & ":" & a & i & "").Select
Selection.Copy
Sheets("" & n2 & "").Select
'Range("b3").Select
lr2 = Range("b65536").End(xlUp).Row
Range("B" & lr2 + 1 & "").Select
ActiveSheet.Paste
End If
Next
'Application.Visible = True
'formatSheet
End Sub

Resources