I am new to writing macros or using VBA, and I have run into a problem that is hopefully easy to fix. I am currently working on a project in Excel that, after clicking a button with the macro attached to it, will allow me to copy and paste data from one master sheet to two others, based on a value (1a or 1b) in column L. The macro I have so far, which is included below, works well with the copy/paste element, but I would love to have the copied data auto-sort by date and time (column J) from oldest to newest when it is pasted into the destination sheet. The date/time format is MM/DD/YY HH:MM AM or PM.
Sub EGS_CVS_Sorting()
Dim lr As Long, lr2 As Long, r As Long
lr = Sheets("template").Cells(Rows.Count, "L").End(xlUp).Row
For r = lr To 2 Step -1
Select Case Sheets("template").Range("L" & r).Value
Case Is = "1a"
lr2 = Sheets("EGS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("EGS lines").Range("A" & lr2 + 1)
Case Is = "1b"
lr2 = Sheets("CVS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("CVS lines").Range("A" & lr2 + 1)
End Select
Next r
End Sub
Thank you!
did none of the 541000 findings on google for vba excel sort catch your interest?
Check if this leads you in the right direction please but adjust the range for the data you want to sort, check about the headers etc:
Sub EGS_CVS_Sorting()
Dim lr As Long, lr2 As Long, r As Long
lr = Sheets("template").Cells(Rows.Count, "L").End(xlUp).Row
For r = lr To 2 Step -1
Select Case Sheets("template").Range("L" & r).Value
Case Is = "1a"
lr2 = Sheets("EGS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("EGS lines").Range("A" & lr2 + 1)
Case Is = "1b"
lr2 = Sheets("CVS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("CVS lines").Range("A" & lr2 + 1)
End Select
Next r
With Sheets("EGS lines")
lr = .Cells(Rows.Count, "L").End(xlUp).Row
Range("A1:L" & lastrow).Sort key1:=Range("J1:J" & lr), _
order1:=xlAscending, Header:=xlYes
End With
With Sheets("CVS lines")
lr = .Cells(Rows.Count, "L").End(xlUp).Row
Range("A1:L" & lastrow).Sort key1:=Range("J1:J" & lr), _
order1:=xlAscending, Header:=xlYes
End With
End Sub
A good starting point for writing a macro to perform some task you haven't coded before is to simply record a macro doing the task you want done. So if I start with a sample data set that has a date in column J, I start recording a macro, sort the data by column J, stop the recording, and look at the code. I get this:
Sub Sorter()
'
' Sort Macro
'
'
Range("J1").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:= _
Range("J1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("All Active Clients").Sort
.SetRange Range("F2:J23")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
This manually codes that I've selected cell J1, then shows me the steps that the sort function goes through. From this, I can narrow down what I actually want to do. For example, selecting J1 is unnecessary, I don't need to worry about the .sortmethod, etc. I can trim the code down to something like the following:
Sub Sorter()
'
' Sort Macro
'
'
Const csDateSt As String = "J1"
Dim shtSort As Worksheet
Dim rngSort As Range
Set shtSort = Sheets("Sheet1")
Set rngSort = shtSort.UsedRange
With shtSort.Sort
.SortFields.Clear
.SortFields.Add Key:= _
Range(csDateSt), _
SortOn:=xlSortOnValues, _
Order:=xlAscending
.SetRange rngSort
.Header = xlNo
.Apply
End With
End Sub
All I have done is reorganise the recorded code, changed a few hard-coded values to constants and variables, and put it all in a With block. I can now use this as a roadmap to put the same kind of structure wherever I need it.
You could even keep your Sorting process as a separate Sub, and just call it when needed, passing it arguments to tell it where the data was, thus:
Sub Sorter(ByVal shtSort As Worksheet, ByVal rngSort As Range, ByVal strKey As String)
With shtSort.Sort
.SortFields.Clear
.SortFields.Add Key:= _
Range(strKey), _
SortOn:=xlSortOnValues, _
Order:=xlAscending
.SetRange rngSort
.Header = xlNo
.Apply
End With
End Sub
Then in your loop you would say something along the lines of:
Select Case Sheets("template").Range("L" & r).Value
Case Is = "1a"
lr2 = Sheets("EGS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("EGS lines").Range("A" & lr2 + 1)
Case Is = "1b"
lr2 = Sheets("CVS lines").Cells(Rows.Count, "L").End(xlUp).Row
Sheets("template").Rows(r).Copy Destination:=Sheets("CVS lines").Range("A" & lr2 + 1)
End Select
Call Sorter(Sheets("EGS Lines"),Sheets("EGS Lines").range("A1").currentregion, "J1")
Call Sorter(Sheets("CVS Lines"),Sheets("CVS Lines").range("A1").currentregion, "J1")
Related
I need Excel to detect the last column I have and sort on that column. I have a macro that generates a new column every time it is used so I cannot use a constant.
Sub sortyness()
Dim sortdata(A1 & ":", Cells(LastRow, LastColumn)) As Range
ActiveWorkbook.Worksheets("Compiled").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Compiled").Sort.SortFields.Add _
Key:=Range(Sorton), Sorton:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Compiled").Sort
.SetRange Range(sortdata)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Here's a screenshot of the sheet:
I am having trouble with getting it to sort by the last column. Can I define the column by looking for the first cell in row 1 that has no data and then use that as a basis to sort? How should I modify my VBA?
Thank you.
I don't know how to edit this thing to get it to not appear as a duplicate, but it's obviously not a duplicate. Mine is more concerned with running a macro on the last column than it is finding the last column.
An vba sort operation actually requires much less code than you get from a recording.
Dim sortdata As Range, LastRow as long, LastColumn as long
With ActiveWorkbook.Worksheets("Compiled")
LastRow = .cells(.rows.count, "A").end(xlup).row
LastColumn = .cells(1, .columns.count).end(xltoleft).column
with .range(.cells(1, 1), .Cells(LastRow, LastColumn))
.Cells.Sort Key1:=.Columns(.columns.count), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlyes
end with
end with
Concerning the second line here:
Dim sortdata(A1 & ":", Cells(LastRow, LastColumn)) As Range
This is not how you assign range. If you want to assign a range, starting on A1 and ending on lastRow, lastColumn, consider this:
Public Sub TestMe()
Dim lastRow As Long: lastRow = 5
Dim lastCol As Long: lastCol = 10
Dim sortData As Range
Set sortData = Range("A1:" & Cells(lastRow, lastCol).Address)
Debug.Print sortData.Address
End Sub
In the above case the range is assigned to the ActiveSheet, which is not always what you may need. If you want to avoid assigning to the ActiveSheet, you should specify the worksheet as well:
With Worksheets("Compiled")
Set sortData = .Range("A1:" & .Cells(lastRow, lastCol).Address)
End With
The two dots in the code above .Range and .Cells will make sure that you refer to the Worksheets("Compiled") and thus will save some problems in the future.
Sort the "last" column with a single line of VBA:
Columns(ActiveSheet.UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count)._
Column).Sort key1:=Columns(ActiveSheet._
UsedRange.Columns(ActiveSheet.UsedRange.Columns.Count).Column)
...which is exactly the same as:
Sub SortLastColumn()
With ActiveSheet.UsedRange
Columns(.Columns(.Columns.Count).Column).Sort key1:=Columns(.Columns(.Columns.Count).Column)
End With
End Sub
I want to do an expanded sort on 2 columns (the columns never change). The code should first sort column D, and then sort column E. While I can use the macro recorder to accomplish this, it produces about 20 lines of code, when in reality, I know it can be done in about 5 or 6.
The below piece of code works for one column, although I think even it can be cleaned up some.
Worksheets("CSAT Details").Sort.SortFields.Add Key:=Range("E1"), SortOn:=xlSortOnValues, Order:=xlAscending
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
With Worksheets("CSAT Details").Sort
.SetRange Range("A2:F" & lastRow)
.Orientation = xlTopToBottom
.Apply
End With
I have created the below code to attempt to sort on the 2 columns, but it does not yet work, giving a
448 named argument not found error
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("CSAT Details").Sort.SortFields.Add _
Key1:=Range("D1"), SortOn1:=xlSortOnValues, Order1:=xlAscending, _
Key2:=Range("E1"), SortOn2:=xlSortOnValues, Order2:=xlAscending
With Worksheets("CSAT Details").Sort
.SetRange Range("A2:F" & lastRow)
.Orientation = xlTopToBottom
.Apply
End With
I am not sure what I am missing.
Something like the following (simply specify your range before running):
Sub foo()
Range("A1:G6").Sort Key1:=Range("E1"), Order1:=xlAscending, Key2:=Range("D1") _
, Order2:=xlAscending, Header:=xlGuess, OrderCustom:=1, MatchCase:= _
False, Orientation:=xlTopToBottom
End Sub
Something like this should work for you:
Sub tgr()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = ActiveWorkbook.Sheets("CSAT Details")
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
With ws.Range("D1:E" & LastRow)
.Sort .Resize(, 1), xlAscending, .Offset(, 1).Resize(, 1), , xlAscending, Header:=xlYes
End With
End Sub
I have created a program which looks for items in Column A or Column I to change. If column I changes, it deletes and moves the row to a new sheet. If Column A changes, it should sort all of the data. However, when the second Application.Intersect(KeyCells2, Range(Target.Address)) is called, it errors out telling me I have a run-time error 424. Why is this happening? It seems to have both a key cells range and a target.address.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Dim KeyCells2 As Range
Dim LastRowCompleted As Long
Dim RowToDelete As Long
Dim CurCell As String
RowToDelete = 0
LastRow = Sheets("Current").Cells(Sheets("Current").Rows.Count, "A").End(xlUp).Row
LastRowCompleted = Sheets("completed").Cells(Sheets("completed").Rows.Count, "A").End(xlUp).Row
LastRowCompleted = LastRowCompleted + 1 'Next row after last row
Set KeyCells = Range("I3:I16384")
Set KeyCells2 = Range("A3:A16384")
CurCell = ActiveCell.Address
If Not Application.Intersect(KeyCells, Range(Target.Address)) Is Nothing Then
Application.EnableEvents = False
'Cut and Paste Row
Target.EntireRow.Copy Sheets("completed").Range(LastRowCompleted & ":" & LastRowCompleted)
'Mark to delete row
RowToDelete = Target.EntireRow.Row
Call DeleteRow(RowToDelete)
Application.EnableEvents = True
End If
Range(CurCell).Select
If Not Application.Intersect(KeyCells2, Range(Target.Address)) Is Nothing Then
Application.EnableEvents = False
'Sort
MsgBox "lastrow completed: " & LastRow
Range("A3:Z" & LastRow).Select
ActiveWorkbook.Worksheets("current").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("current").Sort.SortFields.Add Key:=Range("A3:A" & LastRow) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("current").Sort.SortFields.Add Key:=Range("B3:B" & LastRow) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("current").Sort.SortFields.Add Key:=Range("E3:E" & LastRow) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("current").Sort
.SetRange Range("A3:J" & LastRow)
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range(CurCell).Select
Application.EnableEvents = True
End If
End Sub
Sub DeleteRow(Row As Long)
If Row > 0 Then
Rows(Row).EntireRow.Delete Shift:=xlUp
End If
End Sub
If you delete the row in the first If block then Target no longer exists, so you can't use it in your second If block.
As a fix you could exit the Sub after deleting the row.
P.S. - that "auto-sort" seems like it would be pretty annoying if you're trying to edit data...
EDIT: I just noticed the VBA script isn't working at all, it looks like it is just sorting by the first column as I am getting some funny results :S?
I am using the following VBA to sort by all columns on the sheet.
Sub SortVariableColumns()
Dim strLastCol As String
Dim lngLastCol As Long
Dim sht As Worksheet
Set sht = ActiveSheet
With ActiveSheet
lngLastCol = sht.Cells.Find("*", SearchOrder:=xlByColumns, LookIn:=xlValues, SearchDirection:=xlPrevious).Column
strLastCol = Split(sht.Cells(1, lngLastCol).Address, "$")(1)
sht.Columns("A:" & strLastCol).Select
sht.Sort.SortFields.Clear
sht.Sort.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal ', Header:=xlYes
End With
With sht.Sort
.SetRange Columns("A:" & strLastCol)
.Header = xlYes
.MatchCase = True
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("A1").Select
End Sub
However, it isn't matching case for some reason. The sort works for everything but the case of the words.
Also, is there anyway to make this then move onto the next sheet (i.e. if I selected activeworksheets) - I tried using
Dim sht As Worksheet
For Each ws In ActiveWindow.SelectedSheets
this but kept failing, I guess it has something to do with having to reset the IngLastCOl/StrLastCol holding from the first part of the VBA?
Many thanks.
What's with this as well?
Dim sht As Worksheet
For Each ws In ActiveWindow.SelectedSheets
Where have you defined ws variable? I am not suprised if this code fails at every line or never run at all. These are some fundamental issues.
#boncoDigo
I think I mispasted the code - the code wasn't actually failing on anything related to that! Sorry.
This can now be closed. I have worked out how to do it.
For those interested, this is the code that I used (can be easily amended to loop through sheets):
Sub SortVariableColumns()
Dim finalcolumn As Integer
Dim FinalRow As Integer
Dim sht As Worksheet
Set sht = ActiveSheet
sht.Sort.SortFields.Clear
With ActiveSheet
finalcolumn = Cells(1, Application.Columns.Count).End(xlToLeft).Column
FinalRow = Cells(Application.Rows.Count, 2).End(xlUp).Row
For N = 1 To finalcolumn Step 1
sht.Sort.SortFields.Add Key:=Range(Cells(2, N), Cells(FinalRow, N)), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
Next N
End With
With sht.Sort
.SetRange Range(Cells(1, 1), Cells(FinalRow, finalcolumn))
.Header = xlYes
.MatchCase = True
.Orientation = xlTopToBottom
.Apply
End With
End Sub
I have a table with header and data in columns from A to D with changing row number (number of rows is more than 66800). I'd like to sort data from Z to A order by column C.
There are a lot of different solutions in VBA on internet, but none worked correctly for me.
My code gives me an error:
Sub SortDescending()
Dim lRow As Long
Dim lCol As Long
lRow = Sheets("atm_hh").Cells(Rows.Count, 1).End(xlUp).Row
lCol = Sheets("atm_hh").Cells(1, Columns.Count).End(xlToLeft).Column
With Sheets("atm_hh")
.Select
.Range("A2:" & Cells(lRow, lCol).Address).Sort Key1:=Range("C2"), _
Order1:=xlDescending, _
Header:=xlGuess, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom
End With
End Sub
try
Sub SortDescending()
Dim sh As Worksheet
Set sh = Sheets("atm_hh")
Dim lRow As Long
Dim lCol As Long
lRow = sh.Cells(Rows.Count, 1).End(xlUp).Row
lCol = sh.Cells(1, Columns.Count).End(xlToLeft).Column
Dim cell As Range
For Each cell In sh.Range("C2:C" & lRow)
cell = WorksheetFunction.Substitute(cell, ",", ".")
Next
Columns("C:C").NumberFormat = "0.0"
sh.Cells.AutoFilter
sh.AutoFilter.Sort.SortFields.Clear
sh.AutoFilter.Sort.SortFields.Add Key:=Range("C1:C" & lRow), _
SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With sh.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
sh.AutoFilterMode = False
End Sub