Excel macro - keeping lines with highest priority weight - vba

I have an excel document that has the following column data:
Country,AnimalName,Year,ResultsQuality(1-6),ResultA,ResultB,ResultC.....ResultZ
ResultQuality is an indicator of how accurate the result in the line (ResultA-ResultZ), the highest quality is ResultsQuality=1, the lesser quality level is ResultsQuality=6.
Here is some rows examples:
row#1: US,Camel,1985,2,111,222,333.....999
row#2: US,Camel,1985,5,114,227,338.....958
row#3: CANADA,Camel,1985,3,214,257,638.....858
row#4: CANADA,Shark,1985,1,14,27,38.....8
row#5: CANADA,Shark,1985,2,14,257,3.....628
row#6: CANADA,Shark,1985,4,14,25,63.....568
row#7: CANADA,Shark,1985,6,14,25,6.....838
As you see, the [Country,AnimalName,Year] key can contain one or more lines that has different resultQuality in it.
The macro should:
Go through all the lines, and for each [Country,AnimalName,Year] key - keep the highest quality results line. The other less quality rows for that [Country,AnimalName,Year] should be removed.
After running the macro on the 3 rows above - the results should be:
row#1: US,Camel,1985,2,111,222,333.....999
row#2: CANADA,Camel,1985,3,214,257,638.....858
row#3: CANADA,Shark,1985,1,14,27,38.....8
Thanks allot!

This can actually be accomplished without declaring a single variable. Removing duplicates works from the bottom to the top so if the data is correctly sorted and the appropriate columns supplied to determine duplication, the operation should be dead easy.
Sub Highest_Priority_Weight()
With ActiveSheet.Cells(1, 1).CurrentRegion
'this method can only use three key columns on a sort so we do it twice
.Cells.Sort Key1:=.Columns(4), Order1:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
.Cells.Sort Key1:=.Columns(1), Order1:=xlAscending, _
Key2:=.Columns(2), Order2:=xlAscending, _
Key3:=.Columns(3), Order3:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
'now that the best are at the top, dedupe to clear all others
.RemoveDuplicates Columns:=Array(1, 2, 3), Header:=xlYes
End With
End Sub
That should turn this,
    
.. into something like this,
    
For Excel, that's the quickest way I know of. A subsequent sorting routine could be added after the .RemoveDuplicates operation if you prefer some other displayed format.

Related

VBA Macros How to put in date order then numerical order?

Just as the title says, how can I put an excel sheet in date order, then numerical order? I know how to do these things separately, but the problem is, is that I need it to stay in date order and THEN be in numerical order. Once I put it in numerical order, the dates become mixed up again. The Date is in Column A while the data is in Column B.
Try,
with worksheets("sheet1")
.Cells.Sort Key1:=.Columns(1), Order1:=xlAscending, _
Key2:=.Columns(2), Order2:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlyes
end with
Use the Sort option from the Data menu

Autofilter does not filter anything when Criteria is not met

I have a segment of VBA that looks to autofilter out all the rows in which column 37 is blank. It works great, EXCEPT when there is nothing in the column for the entire data set. Then, instead of filtering away everything but the header row, autofilter does not filter any rows out. This results in the adding of the comment "Expected Waste to all the rows instead of just the ones with a value in column 37. Code is below. Any help on what I am doing wrong would be much appreciated.
' Filter Data by ExpectedWaste
Sheets("Data").Columns("A:AQ").AutoFilter Field:=37, Criteria1:="<>"
' Add expected Waste comment
Sheets("Data").Range("AQ2:AQ" & lastRow).FormulaR1C1 = "Expected waste"
' Unfilter Data
If (Sheets("Data").AutoFilterMode And Sheets("Data").FilterMode) Or
Sheets("Data").FilterMode Then
Sheets("Data").ShowAllData
End If
Typically, I test for visible cells before performing any actions.
with Sheets("Data").Cells("A1:AQ" & lastRow)
.AutoFilter Field:=37, Criteria1:="<>"
with .resize(.rows.count-1, .columns.count).offset(1, 0)
if cbool(application.subtotal(103, .cells)) then
'perform actions on .Specialcells(xlcelltypevisible) here
.columns("AQ").Specialcells(xlcelltypevisible).value = "Expected waste"
end if
end with
end with
I don't think AutoFilter works with blank columns. Check if there is anything to be filtered first, something along the line of Cells(Rows.Count, 37).End(xlUp).Row > 1 because otherwise the code you have wrote Sheets("Data").Range("AQ2:AQ" & lastRow).FormulaR1C1 = "Expected waste" fills the whole column.

sort and subtotal preselected data

I'm working with a worksheet and at some point within there is a list of costs. However this list changes so can have varying numbers of rows. My ultimate goal is to sort and then subtotal this list of costs. Because the number of rows I want to sort and subtotal are always different, I was thinking I could make a macro that would only work off of preselected data eg the user to select the cells range to apply to be sorted and subtotalled. I can't just work off of all active cells, as there are some rows I don't want to include in the sort and subtotal.
I've recorded the following simple macro to sort and subtotal data, however, you'll note it only works for the cells that were selected when I recorded the macro. Does anybody know how to modify the macro so that the user can firstly manually select the cells range with the mouse and then click a button that automatically sorts the preselected data and subtotals it? any help very appreciated, thank you.
Sub Sort_and_Subtotal_CheckBox()
ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort.SortFields.Add Key:=Range( _
"B151:B159"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("B151:K156").Select
Selection.Subtotal GroupBy:=1, Function:=xlSum, TotalList:=Array(10), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
End Sub
Try this code. This will allow the user to select the range by using an Input box.
Dim SortRng As Range
Set SortRng = Application.InputBox("Select the range to sort", "Select Range", 0, , , , , 8)
SortRng.Select
Selection.Sort Key1:=SortRng, Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Range("A1").Select
If you would like to obtain the selected range, you could simply request Selection.Address in VBA. However, I believe that this assumes that the selection is a block of cells, so this might not always give the desired result (e.g. in case of multiple selected ranges). Another solution might be to convert the list of costs to a table. In your macro you can then simply refer to a named range, namely, the column in the newly created table. The table will work as a dynamic named range and will always include the entire range of values in it. If you can be sure that there will be no data below the list of costs, a second option would be to check the last row that is not empty within the column where the list of costs is stored. Something in the likes of .Cells(.Rows.Count, "A").End(xlUp).Row to get the last row of the column that contains the list.

Sort multiple columns by one column

I'm making an email list in Excel with three columns. On the worksheet, I have two buttons, "sort by Name" and "sort by Date added". I would like to sort all three columns by the button chosen so I can find entries faster (I am also entering a separate lookup function later).
Basically, I want the sort function that's already on the toolbar in the worksheet where you can just press it and it knows which column to sort by already. I've seen things for macros and for VBA but all of them are sorting columns by separate parameters, whereas I need these columns linked.
The code produce by the recorder on a Range.Sort method is very verbose and can be chopped down quite a bit to what is essential.
If columns A:C were Name, Email, Date Added then this will sort by Name first, then Date Added.
with worksheets("sheet1") '<~~ set this properly!
with .cells(1, 1).currentregion '<~~ assumes data starts in A2 with a header row in A1:C1
.Cells.Sort Key1:=.Columns(1), Order1:=xlAscending, _
Key2:=.Columns(3), Order2:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
end with
end with
This will sort by Date Added first, then Name.
with worksheets("sheet1") '<~~ set this properly!
with .cells(1, 1).currentregion '<~~ assumes data starts in A2 with a header row in A1:C1
.Cells.Sort Key1:=.Columns(3), Order1:=xlAscending, _
Key2:=.Columns(1), Order2:=xlAscending, _
Orientation:=xlTopToBottom, Header:=xlYes
end with
end with
You can have up to 3 keys. Any more than that and you have to run the routine twice. The opposite of xlAscending is of course xlDescending.
The best way I've found to find something that's already on the toolbar is to use the "Macro Recorder" in a blank/new workbook, and then look at the code.
Are the columns adjacent to each other? Because if so you can use something like this;
//Alright, so this is if you wanted each of the columns to have their
//own values that you are sorting by, if you just want one criteria,
//just use one of the lines
Dim varName as String
Dim varDate as String
Dim varExtra as String
ActiveSheet.Range("A:C").AutoFilter Field:=1, Criteria1:=varName
ActiveSheet.Range("A:C").AutoFilter Field:=2, Criteria1:=varDate
ActiveSheet.Range("A:C").AutoFilter Field:=3, Criteria1:=varExtra
Basically, it's saying for the three columns given, go find the field (which will correspond to a column) indicated and filter by the criteria. You can also use a string value in the Criteria spot instead of a variable.

excel vba sorting currency column descending

I have a sheet with 2 columns A has shopnames and B has currency values
I want to sort in descending order column B
Here's what I have done:
With Sheets("helpsheet")
.Sort Key1:=Range("A"), Order1:=xlDescending, Header:=xlYes
End With
It doesn't work. What do I have to do differently?
There are some options of sorting available in VBA. The simplest way to improve you code is to add a range of data which you want to sort. Therefore you need to improve your code to the following:
With Sheets("helpsheet").Range("a1").CurrentRegion
.Sort Key1:=Range("B1"), Order1:=xlDescending, Header:=xlYes
End With
What I did:
assumed that your data range starts in Range("A1") and makes a region (therefore I used CurrentRegion property in With line.
I set sorting key to Range("B1") according to information from your question.
If required you could change these points accordingly to your situation.