Sorting Worksheet data by column values using Excel VBA - vba

I have next userform developed in vba, which takes info from a worksheet for displaying info
I want to order all the info aphabetically by a Segment, this is the code:
Function llenarDatosTabla()
Dim vList As Variant
Dim ws As Worksheet: Set ws = Worksheets(BD_PRODXSIST)
ListBox1.Clear
With ws
If (IsEmpty(.Range("AA2").Value) = False) Then
Dim ultimoRenglon As Long: ultimoRenglon = devolverUltimoRenglonDeColumna("A1", BD_PRODXSIST)
vList = ws.Range("AA2:AA" & ultimoRenglon & ":AL2").Value
If IsArray(vList) Then
Me.ListBox1.List = vList
Else
Me.ListBox1.AddItem (vList)
End If
End If
Me.ListBox1.ListIndex = -1
End With
Set vList = Nothing
Set ws = Nothing
End Function
how to make it ordered by 'AD' (SEGMENTO) column???

You can sort your Excel Worksheet in ascending order using VBA statement like the following:
Columns("A:XFD").Sort key1:=Range("AD:AD"), order1:=xlAscending, Header:=xlYes
Note: in the column range Columns("A:XFD") instead of XFD enter the last used column pertinent to your case, e.g. Columns("A:DD").
Hope this will help.

To sort a data table, use Excel Names in conjunction with the CurrentRegion function. This is less risky than hard-coding column references and can be done in two simple steps.
The reason it's preferable to specifying columns is that if you get the columns wrong or they change later, you'll scramble your data! When you perform the sort, the cells in any omitted column(s) will remain where they are, becoming part of the wrong rows. And this is exactly what will happen if you add further columns later, unless you remember to update your VBA.
Here are the two simple steps for using this approach. For this example, I've chosen a data table with four columns and four rows:
We are going to sort by COL3 descending. The cells in the other three columns share identical values, enabling us to readily verify they all stay with the correct rows.
Step 1: choose a cell in the data table that's unlikely to ever be removed, such as the header of a column you intend to make permanent, and define a Name for this cell. You can define the name by selecting the cell and typing directly in Excel's Name dropdown above the worksheet. Here I've used the name RegionTag:
Straight away, CurrentRegion can reference the whole data table just from this. You can see it in action if you code a line of VBA to select the table:
Range("RegionTag").CurrentRegion.Select
This is the result:
That's just for illustration, showing the power of the Name/CurrentRegion combination. We don't need to select the table in order to sort it.
Step 2: define a second Name, this time for the column you want to sort by:
Make sure the Name refers to the entire column, selected by clicking the column header, rather than just a range of cells in the column.
That's it! With these two Names defined, we can sort the data table without concerning ourselves with its rows and columns, even if more are added later:
Range("RegionTag").CurrentRegion.Sort _
key1:=Range("SortCol"), order1:=xlDescending, Header:=xlYes
Here is our data table sorted using the above statement:

Related

How to copy/paste formula in filtered/visible cells via VBA in Excel

I am struggling with copying and pasting formula from one column to another one within using filter in another column.
I got a table with 52 columns (number of rows is changing each month).
In column AW (#49) I have applied filter. It shows only CTD.
After applying this filter I need to copy formula from column AH to column AG. Of course I need to apply this only for filtered/visible cells.
The code I have written is copying/pasting this formula into all cells in column AG (it doesn't consider my filter in column AW).
Another problem is that when applying the filter in column AW then the first visible row doesn't need to be all the time AH2 but it can be e.g. AH15 or whatever. I guess this could be avoid via some dynamic solution. Unfortunately I have no clue how to do it.
Afterwards I would like to apply the same for filters in another columns.
Many warm thanks in advance for any hint! :)
This is my code:
Sub ApplyFilterInColumnAW()
Sheets("DATA").Select
ActiveSheet.ListObjects("tb_DATA").Range.AutoFilter Field:=49, Criteria1:="CTD"
Range("AG2").Select 'dynamic solution?
ActiveCell.FormulaR1C1 = "=[#[Service/Log Formula]]" 'header name of column AH
End Sub
Range.Copy and Range.Paste only work on visible cells. In my example I target the cells in the column using the Column Header.
Sub ApplyFilterInColumnAW()
Const TagetColumnLabel = "Test"
Dim tbl As ListObject
Set tbl = Sheets("DATA").ListObjects("tb_DATA")
With Sheets("DATA")
.ListObjects("tb_DATA").Range.AutoFilter Field:=49, Criteria1:="CTD"
tbl.ListColumns(TagetColumnLabel).DataBodyRange.FormulaR1C1 = "=tb_DATA[[#This Row],[Service/Log Formula]]"
End With
End Sub

How to move parts of a dynamic pivot table to a separate table?

I have pivot table pulling data from a query from a proprietary database system we use at work. I'm trying to figure out a way to move certain parts of the pivot table to a different sheet where it wouldn't exist as a pivot table there. My problem I'm running into is that the table changes the number of columns and rows depending upon the types and amounts of things that we shipped that shift, so I can't have it simply have my new table equal the cell values in the pivot table.
This is an example of the pivot data having fewer columns and rows based on what occurred that shift at work.
The reason why I would like this in a regular table as opposed to a pivot table is because there's other calculations I'd like to put into the table that extend beyond a pivot table's capabilities (ex. have the user id be displayed as their name, and have a weighted system based off of what the driver moves, but I suppose that's irrelevant.)
I've been poking around the internet, and it seems that the majority of answers to this issue deal with static tables. Any help would be appreciated!
Let's assume you want the cell to have the value from "BEER Total" for "M307577". Then this would be the formula you put in the cell:
=VLOOKUP("M307577",A5:Z100,MATCH("BEER Total",A5:Z5,0),FALSE)
"A5:Z100" would be the whole pivot table and "A5:Z5" would be the first row containing variables.
As you mentioned you are not familiar with VBA, I would suggest this approach:
Use the first column and first row of the second sheet as a reference. Refer to all the variables from the pivot table there (refer to the cell containing IDs and Variables, and pull the formula to the last row for IDs and last column for variables (or a reasonable range as last column and row would not be sufficient)). This will leave you with zeros, empty cells from the pivot table sheet, but will have all the names that you need.
Then refer to those cells and use the aforementioned formula (instead of names, use the cells that you just created).
Whenever the pivot table updates, those cells will be updated as well and you will see the values for the corresponding ID and Variable.
I think you want the GETPIVOTDATA function. Determine what your logic will look like and click on the appropriate combination of cells. Excel will automatically setup the GETPIVOTDATA function appropriately for you.
http://www.contextures.com/xlPivot06.html
Also, if the last used columns and last used rows are changing, you will probably need a Macro to help you with your task.
Sub LastRowInOneColumn()
'Find the last used row in a Column: column A in this example
Dim LastRow As Long
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
MsgBox LastRow
End Sub
Sub LastColumnInOneRow()
'Find the last used column in a Row: row 1 in this example
Dim LastCol As Integer
With ActiveSheet
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
MsgBox LastCol
End Sub
You can use a combination of functions to help you get the last used cell in a specific range.
https://exceljet.net/formula/address-of-last-cell-in-range
From there, I think you can figure out your next steps.
Post back with more information if you still have trouble with this, or start a new post if your question is answered.

How to delete unselected columns from range

I am new to VBA and am trying to delete unwanted columns loaded from a .csv file. I am importing a large amount of data but then I ask the user what columns they want to keep going by "ID num.". There are a lot of columns with different ID no. and I want to ask the user what they want to keep and delete the rest.
The problem is I need to delete all the other columns the user didn't want but I still need to keep the first 6 columns and the last two columns as that is different information.
Here is what I have so far:
Sub Select()
'the below will take the users inputs
UserValue = InputBox("Give the ID no. to keep seperating with a comma e.g"12,13,14")
'the below will pass the user inputs to the example to split the values
Call Example(UserValue)
End Sub
Sub Example(UserValue)
TestColArray() = Split(UserValue, ",")
For Each TestCol In TestColArray()
' keep all the columns user wants the delete the rest except the first 6 columns and last 2
Next TestCol
End Sub
That is what I have so far, it is not much but the user could put in a lot of columns with different ID number in the input box the way the Excel sheet is laid out all the ID no.s are in row 2 and the first 6 and last 2 columns are blank of row 2 since the ID no. does not apply. I hope that helps.
try this (commented) code:
Option Explicit '<--| use this statament: at the cost of having to declare all used variable, your code will be much easier to debug and maintainable
Sub MySelect()
Dim UserValue As String
'the below will take the users inputs
UserValue = Application.InputBox("Give the ID no. to keep seperating with a comma e.g: ""12,13,14""", Type:=2) '<--| use Type:=2 to force a string input
'the below will pass the user inputs to the example to split the values
Example UserValue '<--| syntax 'Call Example(UserValue)' is old
End Sub
Sub Example(UserValue As String)
Dim TestCol As Variant
Dim cellsToKeep As String
Dim firstIDRng As Range, lastIDRng As Range, IDRng As Range, f As Range
Set firstIDRng = Range("A2").End(xlToRight) '<-- first ID cell
Set lastIDRng = Cells(2, Columns.Count).End(xlToLeft) '<-- last ID cell
Set IDRng = Range(firstIDRng, lastIDRng) '<--| IDs range
cellsToKeep = firstIDRng.Offset(, -6).Resize(, 6).Address(False, False) & "," '<--| initialize cells-to-keep addresses list with the first six blank cells at the left of first ID
For Each TestCol In Split(Replace(UserValue, " ", ""), ",") '<--| loop through passed ID's
Set f = IDRng.Find(what:=TestCol, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False) '<--| search for the current passed IDs range
If Not f Is Nothing Then cellsToKeep = cellsToKeep & f.Address(False, False) & "," '<--| if the current ID is found then update cells-to-keep addresses list
Next TestCol
cellsToKeep = cellsToKeep & lastIDRng.Offset(, 1).Resize(, 2).Address(False, False) '<--| finish cells-to-keep addresses list with the firts two blank cells at the right of last ID
Range(cellsToKeep).EntireColumn.Hidden = True '<-- hide columns-to-keep
ActiveSheet.UsedRange.EntireColumn.SpecialCells(xlCellTypeVisible).EntireColumn.Delete '<--| delete only visible rows
ActiveSheet.UsedRange.EntireColumn.Hidden = False '<-- unhide columns
End Sub
it's assumed to be working with currently active worksheet
A simple google search produces this. On the first page of results too. Perhaps this will suit your needs.
If the data set that needs to be deleted is really large (larger than the ranges you want to keep too.) Then perhaps only select the columns you want to have whilst you import the csv? This stackoverflow question shows how to import specific columns.
EDIT:
So from what I believe the OP is stating as the problem, there is a large csv file that is being imported into excel. After importing there is alot of redundant columns that should be deleted. My first thought would be to only import the needed data (columns) in the first place. This is possible via VBA by using the .TextToColumns method with the FieldInfo argument. As stated above, the stackoverflow question linked above provides a means of doing so.
If the selective importing is not an option, and you are still keen on making an inverse of the user selection. One option would be to create 2 ranges (one being the user selected Ranges and the second being the entire sheet), you could perform an intersect check between the two ranges and delete the range if there is no intersection present (ie. delete any cell that is not part of the users selection). This method is provided by the first link I supplied and is quite straight forward.

Copy row from one sheet and insert copied row under last row in another sheet

I am in need of your expert assistance.
I am trying to write some code that will copy rows and insert the copied row below the last row in another sheet.
I have a Global sheet that has the data i will be copying. It will need to look in column Q.
I think the problem will be when trying to copy the data, the data in column G is the text name of a Contract Code. But the sheets are name with the Number version.
for example i have a row that has BRREPAIRS in column Q, I need this to copy to Sheet 2870, then i have a row that has BRVOIDS in column Q, I need this to copy to Sheet 2781.
I could have multiple different Contract names so i think i might need to define the text to equal a sheet. So maybe Set BRVOIDS = Sheet.name("2781") Set BRREPAIRS = Sheet.name("2780") and so on until all sheets are defined.
When the data gets copied i need it to find the last row in column a that has data, when it is found it will insert the copied row into the sheet. for example EntireRow.Insert Shift:=xlDown.
I dont have any code at the moment. I would really appreciate all the assistance.
You don't need to do things like Set BRVOIDS = Sheet.name("2781"). In fact, that would be positively harmful since then you would need to run the data in Column Q through a possibly large Select statement to know what variable to use. Instead, you could write a function like
Function TargetSheet(ContractName As String) As Worksheet
'code which uses your secret list to determine target sheet
'Maybe a Select statement, Maybe a Vlookup -- who knows?
Set TargetSheet = 'sheet your code determined
End Function
Sounds like your code will be scanning down column Q, determining where to copy the corresponding row to. Once you get the above function working, you could combine it with something like this:
Function LastRow(TargetCol As Variant, Optional ws As Variant) As Range
'assumes TargetCol is something like 1 or "A"
Dim n As Long
If IsMissing(ws) Then Set ws = ActiveSheet
n = ws.Cells(1, TargetCol).EntireColumn.Rows.Count
Set LastRow = ws.Cells(n, TargetCol).End(xlUp).EntireRow
End Function
This returns as a range the last row containing data (or row 1 if the column is empty) in a specified column in a specified worksheet (which defaults to the Active sheet).
You haven't given enough to go on, but something along the lines of
LastRow("A",TargetSheet(Range("Q" & i).Value)).Insert Shift := xlDown
Might be what you are looking for. Why don't you try to work it out and ask another question (if need be) once you have some actual code?

VBA - EXCEL Remove columns except specified range

I was looking for answers however I can't find one so specific.
I am trying to write macro which will be easy to use for people without any programming knowledge.
So we use pricing template where you can see prices for many different countries. I want to create a macro which will copy whole tab and remove unwanted columns depends from for which country it is creating file. (Needed to preserve formulas, I still want to have all the calculation not values).
So first few columns will stay since they are common for all countries, and then all the columns except selected range should be deleted. Ranges are specified in separate tab and will be stored in array.
Example:
Belgium
First Column: CJ
Last Column: CQ
So let's say in first loop first column and last column values are stored, and I want macro remove columns from H to CI and then from CR to HF.
However in next loop first and last will change so delete ranges have to recalculate.
I tried with formulas ASC and CHR but it doesn't work with two letters codes.
Well, if you already know the ranges you want to use, a subroutine like this could remove a range of columns, minus an exception range.
I'm just looping through the columns and checking for an intersection. If there is no intersection between the column being tested and the exception range, we add it to the list of columns to be deleted.
Public Sub RemoveColumnsExcept(removeRange As Range, exceptRange As Range)
Dim deletionRange As Range
Dim columnRange As Range
For Each columnRange In removeRange.Columns
If Intersect(columnRange, exceptRange) Is Nothing Then
If deletionRange Is Nothing Then
Set deletionRange = columnRange
Else
Set deletionRange = Union(deletionRange, columnRange)
End If
End If
Next columnRange
If Not deletionRange Is Nothing Then
deletionRange.Delete xlShiftToLeft
End If
End Sub
Public Sub Test()
RemoveColumnsExcept Sheet1.[B:J], Sheet1.[G:I]
End Sub
You could use named ranges to keep track of the columns you want deleted. That or column headers and a loop looking for some value like country code in a specific row.