Sort groups and keep spaces - excel

I'm looking for help on a code where the end user hits a button and it sorts the data, but keeps the "groups" together (from columns A through AA) as well as the spaces between tasks.
I've done some research online, but wasn't able to get anything to work, so I don't even have a base code to start from.
Here's some pictures to show what I'm trying to accomplish.
The first image shows the tasks as they may have been entered, but then we assign priorities after all tasks are entered and, as you can see, they're out of order.
Then I'd like for them to hit that "sort" button on the top left of the image, and it sort the worksheet base upon priority, with 1 being the first task, and going down to the last, but keep the "groups" and the space between tasks, so it ends up looking like this:
Again, columns affected would be from A through AA (i.e., the data needing to stay together spans between those columns).
I don't know if this is even possible, but any help would be GREATLY appreciated.
EDIT:
I created a thread on ExcelForum so I can post an actual spreadsheet... that post is here: https://www.excelforum.com/excel-programming-vba-macros/1362269-sort-groups-and-keep-spaces.html#post5585545

Use 2 spare columns to hold sort order keys.
Option Explicit
Sub sortit()
Dim wb As Workbook, ws As Worksheet
Dim LastRow As Long, r As Long
Dim p As Integer, n As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
With ws
LastRow = .UsedRange.Rows.Count + .UsedRange.Row - 1
' use column AB,AC for sort order
For r = 4 To LastRow
If .Cells(r, "A") > 0 Then
p = .Cells(r, "A")
n = 0
End If
n = n + 1
.Cells(r, "AB") = p
.Cells(r, "AC") = n
Next
With .Sort
.SortFields.Clear
.SortFields.Add Key:=ws.Range("AB4"), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=ws.Range("AC4"), SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.SetRange ws.Range("A4:AC" & LastRow)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' clear columns
.Columns("AB:AC").Clear
End With
MsgBox "Sorted"
End Sub

Related

Value of cell that depends on another dynamic cell within a range

Range A1:A5 is filled with dynamic data, though the data is limited to 5 values, the sequence could differ. It is also possible that only 4 or less is presented. The values are also unique.
Column B's value will depend on Column A.
Example:
A B
1 item2 USD18
2 item1 USD15
3 item3 USD4
4 item5 USD23
5 item4 USD11
How do I accomplish this on VBA?
Quite tricky. Please try this code after adjusting the items marked "change to suit".
Sub SetSequence()
' 156
Const DataClm As Long = 2 ' change to suit (2 = column B)
Const ItemClm As Long = 1 ' change to suit (1 = column A)
Dim Wb As Workbook
Dim Ws As Worksheet
Dim DataRng As Range ' sorted given data (column B in your example)
Dim Results As Variant ' results: sorted 1 to 5
Dim TmpClm As Long ' a column temporarily used by this macro
Dim Tmp As String ' working string
Dim R As Long ' oop counter: rows
Dim i As Long ' index of Results
Results = Array("Item1", "Item2", "Item3", _
"Item4", "Item5") ' modify list items as required (sorted!)
Set Wb = ThisWorkbook ' modify as needed
Set Ws = Wb.Worksheets("Sheet1") ' change to suit
With Ws
With .UsedRange
TmpClm = .Column + .Columns.Count
End With
' create a copy of your data (without header) in an unused column
.Range(.Cells(2, DataClm), .Cells(.Rows.Count, DataClm).End(xlUp)) _
.Copy .Cells(1, TmpClm)
Set DataRng = .Range(.Cells(1, TmpClm), .Cells(.Rows.Count, TmpClm).End(xlUp))
With .Sort.SortFields
.Clear
.Add2 Key:=Ws.Cells(1, TmpClm), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
End With
With .Sort
.SetRange DataRng
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' blanks are removed, if any
Set DataRng = .Range(.Cells(1, TmpClm), .Cells(.Rows.Count, TmpClm).End(xlUp))
' start in row 2 of DataClm and look at next 5 cells
For R = 2 To 6
' skip over blanks
Tmp = .Cells(R, DataClm).Value
If Len(Trim(Tmp)) Then
i = WorksheetFunction.Match(Tmp, DataRng, 0)
.Cells(R, ItemClm).Value = Results(i - 1)
End If
Next R
.Columns(TmpClm).ClearContents
End With
End Sub
The code creates a sorted copy of the items you have in column B and draws the output in column A from the similarly sorted list of results. Blanks are ignored. But if there is one blank in the input list (column B) there will be only 4 items in the sorted input list and therefore none of the items can be assigned "Item 5" in column A.
I've replaced my answer with the one below from your edit which completely changed things.
See if this is what you're looking for:
Dim ValueArr As Variant
ValueArr = Array("USD15", "USD18", "USD4", "USD11", "USD23")
For i = 1 To 5
If Range("A" & i) <> "" Then
Range("B" & i) = ValueArr(Right(Range("A" & i), 1) - 1)
End If
Next i
This code is based off of using the number on the end of item to know which value to put in place. If the row is blank it will skip over it.

Sorting a Range based on sheet variable with VBA

Scenario: I have a sheet and am trying to sort a part of it. Inside the sheet I have a dropdown list, which allows me to select the values (aaa, bbb, ccc). Each of those values represent a column and when selected, the code should sort the range by that column.
Problem: The process works for one of the values in the dropdown list, but not for the others (it runs, but nothing happens).
Code:
Sub ratecolumnssort()
Dim LastRow As Integer
Dim sortColumn As String, sortAgent As String
shtMonitoring.Activate
LastRow = shtMonitoring.Cells(shtMonitoring.rows.count, "B").End(xlUp).row
sortAgent = shtMonitoring.Cells(8, 9) ' this is where the dropdown with values aaa, bbb and ccc is
If sortAgent = "aaa" Then
sortColumn = "F"
ElseIf sortAgent = "bbb" Then
sortColumn = "H"
ElseIf sortAgent = "ccc" Then
sortColumn = "J"
End If
With ActiveSheet.sort
.SortFields.Add key:=Range(sortColumn & "11"), Order:=xlAscending
.SetRange Range("B11", "N" & LastRow )
.Header = xlYes
.Apply
End With
End Sub
Question: What am I doing wrong here?
You need to clear the sort settings first.
With ActiveSheet.Sort
.SortFields.Clear 'add this line
'as before

cut copy paste looped instruction betwene two sheets

I have had some answers to my question below, but despite numerous attempts I think my code is now just a total mess, and cannot fathom where it is wrong.
So I have a range A12:N112 that needs sorted on row A with descending values.
Next I need to copy each row (B:L) where column A has a "1" in it and paste it into the first blank row in another workbook, based on column D being blank. I then need to copy the number generated in column A for the row I have just pasted into, and then paste this back into the original row I copied in row N of the first spreadsheet.
I need this then to loop until we reach the first value of "0" in the first spreadsheet.
Here is my code, and although I can get the sort to work, I cannot get anything at all to copy or paste. This is similar to code i've used before for a single cut copy paste, but cannot get it to work at all here.
Dim r As Long
Dim lr As Long
Dim wkb As Workbook
Dim ws As Worksheet
Dim wkb2 As Workbook
Dim ws2 As Worksheet
Set wkb = ThisWorkbook
Set ws = wkb.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srveurfcl03.nov.com\IS-GBR-GLBISETNRegister$\Serial No Trial\Serialisation Log.xlsx")
Set ws2 = wkb2.Worksheets("SNo Log")
wkb.Activate
ws.Activate
ActiveWorkbook.Worksheets("Data Entry").sort.SortFields.Clear
ActiveWorkbook.Worksheets("Data Entry").sort.SortFields.Add Key:=Range( _
"A12:A112"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("Data Entry").sort
.SetRange Range("A11:N112")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
For r = 12 To lr
If wkb.ws.Cells(r, 1).Value = 1 Then
ws.Cells(r, "B:L").Copy
wkb2.Activate
ws2.Activate
Range("D" & Rows.Count).EndX(x1Up).Offset(1).Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveSheet.Paste
Range("A" & Rows.Count).End(xlUp).Offset(0).Select
Selection.Copy
wkb.Activate
ws.Cells(r, 13).Value.Paste
End If
If wkb.ws.Cells(r, 1).Value = 0 Then
ws.Cells(4, 9).Select
ActiveCell.FormulaR1C1 = "Serial No. Issue complete for this OA"
End If
Range("F5").Select
Next r
Any help would be greatly appreciated as it always is. I've tried to set variables, but cannot get them to work on bits of my code due to object errors so had to go back to the code I know works. But this only does for fixed ranges, which I will not have in this workbook.
Per my comments, you don't need to sort your data, or use Activate. Using Range("D" & Rows.Count).EndX(x1Up).Offset(1) was going in the right direction except you needed to remove the X in EndX. Also, the portion of code below does not make any sense. So you need to clarify what you want, to include an example of the outcome, if needed.
Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveSheet.Paste
Range("A" & Rows.Count).End(xlUp).Offset(0).Select
Selection.Copy
wkb.Activate
ws.Cells(r, 13).Value.Paste
End If
If wkb.ws.Cells(r, 1).Value = 0 Then
ws.Cells(4, 9).Select
ActiveCell.FormulaR1C1 = "Serial No. Issue complete for this OA"
End If
Range("F5").Select
The best way to copy a range is to copy the complete range, not line-by-line. The code below will hide any rows from Range("A12:A112") that do not have a "1" in column A. It will then copy the visible cells in the range using SpecialCells(xlCellTypeVisible) and paste to the first empty cell in ws2.Column(4). It then makes all the rows that were hidden visible again. This code will work if your workbook and worksheet variables are correct.
Dim ws As Worksheet
Dim wkb2 As Workbook
Dim ws2 As Worksheet
Dim Rng As Range
Set ws = ThisWorkbook.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srveurfcl03.nov.com\IS-GBR-GLBISETNRegister$\Serial No Trial\Serialisation Log.xlsx")
Set ws2 = wkb2.Worksheets("SNo Log")
For Each cell In ws.Range("A12:A112")
If cell.Value <> "1" Then
cell.EntireRow.Hidden = True
End If
Next cell
Set Rng = ws.Range("A12:A112").SpecialCells(xlCellTypeVisible)
Rng.Copy Destination:=ws2.Cells(Rows.Count, 4).End(xlUp).Offset(1)
ws.Range("A12:A112").EntireRow.Hidden = False

How to delete rows in an Excel ListObject based on criteria using VBA?

I have a table in Excel called tblFruits with 10 columns and I want to delete any rows where the Fruit column contains Apple. How can I do this?
The following sub works:
Private Sub deleteTableRowsBasedOnCriteria(tbl As ListObject, columnName As String, criteria As String)
Dim x As Long, lastrow As Long, lr As ListRow
lastrow = tbl.ListRows.Count
For x = lastrow To 1 Step -1
Set lr = tbl.ListRows(x)
If Intersect(lr.Range, tbl.ListColumns(columnName).Range).Value = criteria Then
'lr.Range.Select
lr.Delete
End If
Next x
End Sub
The sub can be executed like this:
Dim tbl As ListObject
Set tbl = ThisWorkbook.Worksheets("Sheet1").ListObjects("tblFruits")
Call deleteTableRowsBasedOnCriteria(tbl, "Fruit", "Apple")
Well, it seems the .listrows property is limited to either ONE list row or ALL list rows.
Easiest way I found to get around this was by:
Setting up a column with a formula that would point out to me all rows I would like to eliminate (you may not need the formula, in this case)
Sorting the listobject on that specific column (preferably making it so that my value to be deleted would be at the end of the sorting)
Retrieving the address of the range of listrows I will delete
Finally, deleting the range retrieved, moving cells up.
In this specific piece of code:
Sub Delete_LO_Rows
Const ctRemove as string = "Remove" 'value to be removed
Dim myLO as listobject, r as long
Dim N as integer 'number of the listcolumn with the formula
Set myLo = Sheet1.ListObjects("Table1") 'listobject goes here
With myLO
With .Sort
With .SortFields
.Clear
.Add Key:=.HeaderRowRange(myLO.ListColumns(N)), SortOn:= _
xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
End With
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
On Error GoTo NoRemoveFound
r = Application.WorksheetFunction.Match(ctRemove, .ListColumns(.ListColumns.Count).DataBodyRange, 0)
Range(.parent.name & "!" & .DataBodyRange(r, 1).Address & ":" & .DataBodyRange(.ListRows.Count, .ListColumns.Count).Address).Delete xlShiftUp
'Added the .parent.name to make sure the address is on the correct sure, but it will fail if there are any spaces or characters on the sheet name that will make it need a pair of '.
'The error is just to skip these two lines in case the match returns an error. There's likely a better/cleaner way to do that.
NoRemoveFound:
End With
End sub
Hope it helps...

Trying to refer to columns in Excel using variables. What function should I use?

Trying to sort data in Excel alphabetically by row, but NOT in all of the columns for each row.
For example: Sort J7 through U7 alphabetically, then J8 through U8, all the way down through J2000 through U2000, while keeping each item within its row (like all cells in row 7 should still be in row 7 by the end of it.)
It seems like I'll need to use a macro/VBA for this, as Excel only lets you sort one row at a time alphabetically. If I select more than one row to sort, it still only sorts the first row.
I have done a bit of research as far as what kind of macros I could use for this, but nothing seems to do the job. The one thing I found that was similar to this sorts by number, but can't sort alphabetically.
Here's what I've got at a moment. I recorded a macro of myself selecting and sorting the row so that I could hopefully get all the code for that right at least:
Sub Macro4()
'
' Macro4 Macro
'
' Keyboard Shortcut: Option+Cmd+j
'
Dim lngIndex As Long
Dim strArray(9 To 11000) As String
Dim intCounter As Integer
Dim x As Integer
intCounter = 1
x = 9
For lngIndex = LBound(strArray) To UBound(strArray)
intCounter = intCounter + 1
strArray(lngIndex) = intCounter
x = x + 1
Range("Jx:UNx").Select
ActiveWorkbook.Worksheets("export_729559 (3).xlsx").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("export_729559 (3).xlsx").Sort.SortFields.Add Key:= _
Range("Jx:UNx"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("export_729559 (3).xlsx").Sort
.SetRange Range("Jx:UNx")
.Header = xlNo
.MatchCase = False
.Orientation = xlLeftToRight
.SortMethod = xlPinYin
.Apply
End With
Next
End Sub
I'm getting: Run-time error ‘9’: Subscript out of range And it's highlighting the line: ActiveWorkbook.Worksheets("export_729559 (3).xlsx").Sort.SortFields.Clear
I think the error I'm getting is because it's thinking I mean Column JX, rather than Column Jx, where x is a variable I was trying to use to cycle through each row. It seems like there are a few different ways to use variables instead of directly naming the columns, which I'll need to do to reference a new row through each iteration. Could someone recommend a certain function?
One of the ones I've come across is =OFFSET(), but I'm not sure if that would be a good fit for what I'm trying to do, and I'm having a hard time knowing how to fill it in with the right things.
Something like this:
Sub Macro4()
Dim lngIndex As Long
Dim strArray(9 To 11000) As String
Dim intCounter As Integer
Dim sht As Worksheet, rng As Range
Set sht = ActiveWorkbook.Worksheets("export_729559 (3).xlsx")
Set rng = sht.Range("J10:UN10")
intCounter = 1
For lngIndex = LBound(strArray) To UBound(strArray)
intCounter = intCounter + 1
strArray(lngIndex) = intCounter
With sht.Sort
.SortFields.Clear
.SortFields.Add Key:=rng, SortOn:=xlSortOnValues, _
Order:=xlAscending, DataOption:=xlSortNormal
.SetRange rng
.Header = xlNo
.MatchCase = False
.Orientation = xlLeftToRight
.SortMethod = xlPinYin
.Apply
End With
Set rng = rng.Offset(1, 0)
Next
End Sub
If you want to use x as a variable:
Range("J" & x & ":UN" & x)
If you put that in what you are using, should work.

Resources