The code below makes a copy of the master sheet for each of the cells in the list (Named "Splitcode"), it then filters the first column in the data (Named "MasterData") and deletes any rows that don't have that cell in them. and loops until a sheet is created for every cell.
The code works perfectly on text values on column1 and on the list.
but it won't work on numeric values (e.g account numbers).
I have been told I should be adding a CStr() Function, but I've never used it before so I don't know where to exactly add it.
Sub SplitandFilterSheet()
Dim Splitcode As Range
Sheets("Master").Select
Set Splitcode = Range("Splitcode")
For Each Cell In Splitcode
Sheets("Master").Copy After:=Worksheets(Sheets.Count)
ActiveSheet.Name = Cell.Value
With ActiveWorkbook.Sheets(Cell.Value).Range("MasterData")
.AutoFilter Field:=1, Criteria1:="<>" & Cell.Value,Operator:=xlFilterValues
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
ActiveSheet.AutoFilter.ShowAllData
Next Cell
End Sub
Consider this: CStr( expression )
Dim LValue As String
LValue = CStr(8)
The LValue variable would now contain the string value of "8"
I see that you have Cell.Value in 3 places. Also, check out this link.
https://www.excel-easy.com/examples/number-text-filters.html
Finally, you may want to simplify things a bit. If you have a header row in your range that you don't want to delete, add an offset to the range to exclude it:
ActiveSheet.Range("$A$1:$I$" & lines).Offset(1, 0).SpecialCells _
(xlCellTypeVisible).EntireRow.Delete
Related
I want to do some column formatting but column position is changing every time so how can i use column header instead of Column Alphabet ?
Sub Excel_Format()
Columns("J:J").Select
Selection.NumberFormat = "0"
Selection.Columns.AutoFit
End Sub
You need to start defining a Name for your column. The quickest way to do it is to select the column (Column J in this case) and enter a name in the range/cell selector on the top-left part of your Workbook. See image below:
I have named the column to "MyColumn". You can now use this as a reference in your code, like this:
Sub Excel_Format()
Dim Rng As Range
Set Rng = ActiveSheet.Range("MyColumn")
Rng.NumberFormat = "0"
Rng.Columns.AutoFit
End Sub
Even if you add or remove columns to the left of column J, the reference to MyColumn will remain correct
Please, try the next way. You can use it for any header, only adapting the used constant:
Sub Excel_Format()
Dim ws As Worksheet, RngH As Range
Const myColName As String = "ColumnX" 'your column header
Set ws = ActiveSheet 'use here your necessary sheet
Set RngH = ws.rows(1).Find(myColName)
If Not RngH Is Nothing Then
With RngH.EntireColumn
.NumberFormat = "0"
.AutoFit
End With
Else
MsgBox myColName & " could not be found in the sheet first row..."
End If
End Sub
The header should exist in the first sheet row. If not, you should adapt ws.rows(1).Find( writing the necessary row, instead of `...
Selecting, activating in such a context only consumes Excel resources, not bringing any benefit.
this is a follow up to my post at: Excel VBA: Switch Case to read values from a column
I currently have one working switch statement that looks for a case e.g (493) from Column I, and if it finds 493 it returns "Robotics" in column G.
Now I need to create a second switch statement that looks for a case e.g (EPA0012) from column AN, and if it finds EPA0012 it will display "Accounting" in column AO. The issue I am encountering is that when I run the same code that I used for the first switch statement, instead of it populating the adjacent column with "Accounting", it instead populates every single cell in the column except for the column adjacent to EPA0012 (where it should be populating).
The issue is because of "EPA" as when I removed this and just use 0012 it worked perfectly so I am assuming I need to adjust a variable or something.
The code is as follows:
Public Sub Switch_Statement_EPA()
Dim wsSort As Worksheet
Set wsSort = Workbooks("Test.xlsm").Worksheets(2)
With wsSort
Dim lastRow As Long
lastRow = .Range("AN" & .Rows.Count).End(xlUp).Row
Dim rng As Range
Set rng = .Range("AN2:AN" & lastRow)
Dim cell As Range
For Each cell In rng '<--- the loop
Select Case cell.Value
Case EPA0012
cell.Offset(, 1).Value = "Accounting"
End Select
Next
End With
MsgBox ("Done")
End Sub
I have created a for loop to detect where does an empty value appears in range "E7:AB7". Once done that I want to create a Range from E7 to that empty value so it can copy and paste the data from a Master Sheet only within that range.
For example if it detects an empty value in X7 then the Range must be ("E7:X7").
Here is a sample of the code:
Sub Macro5()
For Each cell In Worksheets("Proof").Range("E7:AB7")
If IsEmpty(cell) Then
Dim Cval As Range
Set Cval = Worksheets("Proof").Range(cell.Address)
Exit For
End If
Next
Sheets("MasterSheet").Range("A3:AG5000").AdvancedFilter Action:= _
xlFilterCopy, CopyToRange:=Range("E7" & ":" & Cval), Unique:=False 'Here is where the dynamic range exists
End Sub
Someone have an idea on how to apply it to the Range function?
Thanks!
Please play a little with the code below.
Private Sub Test()
Dim Rng As Range ' dynamic range in row 7
With Worksheets("Proof")
Set Rng = .Range(.Cells(7, "E"), .Cells(7, "E").End(xlToRight))
' use the line below to include the blank in the range
' Set Rng = .Range(.Cells(7, "E"), .Cells(7, "E").End(xlToRight).Offset(0, 1))
End With
' Debug.Print Rng.Address
Sheets("MasterSheet").Range("A3:AG5000").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=Rng, _
Unique:=False 'Here is where the dynamic range exists
End Sub
Set Rng = .Cells(7, "E").End(xlToRight) sets a range of a single cell, defined as the last used cell before a blank cell, looking from E7 to the right. A range from E7 to that cell therefore excludes the blank cell itself. Therefore, in your example, if E7 itself is blank the code will crash or maybe set a range D7:E7, neither of which you want. Therefore you may prefer to include the blank cell in the range as, in fact, your code suggested.
Your code CopyToRange:=Range("E7" & ":" & Cval) has two flaws, at least one of which proved fatal. One is that you calculate the range at the time of using it. In my code the range is prepared before use so that you can check its address before you feed it to the filter. The other flaw is that you don't specify the sheet on which your range is supposed to exist. Therefore it will be on the ActiveSheet which could be any sheet at all. My code, you may argue, doesn't specify the worksheet, either. That isn't entirely true. Try Debug.Print Rng.Worksheet.Name.
Okay so this one is hard to explain - I have a very large table that has customers, part numbers, price, and revenue. I need to return all customers that use a list of part numbers; so for instance if they use parts ABC and DEF then it would return the customers that use those parts, and the revenue for those customers (I figured I would copy the entire rows to another table or something).
I don't want to see customers that use one part but not the other. I've tried doing autofilters and advanced filters with no luck, but I would rather do this in VBA if possible. I'm not sure which way would be the easiest...
One thought was to pivot the table and sort by customers, but this is very manual and I need to pull these results into another table so I can see the data separately. Any help is much appreciated!
Example table
edited after OP's clarification. see added code
You can use the "xlFilterValues" operator of "AutoFilter()" method of "Range" object.
Assuming first row has headers, here's the "basic concepts" code you asked for:
Dim partListArr As Variant
With Worksheets("MyListSheetName")
partListArr = Application.Transpose(.Range("A1", .Cells(.Rows.Count,1).End(xlUp)).Value)'<--| retrieve the content of its column A cells from row 1 down to its last not empty cell
End With
With Worksheets("MyDataSheetName")
With .Range("Z1", .Cells(.Rows.Count,1).End(xlUp)) '<--| reference its A to Z columns cells from row 1 down to column A last not empty cell
.Autofilter field:=2, Criteria1:=partListArray, operator:=xlFilterValues '<--| filter referenced range on its 2nd field with list of parts
With .Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible) '<--| reference filtered cells, skipping headers
' here your code to handle filtered cells
End With
End With
End With
Since your clarifications you could still use nested AutoFilter()s to catch proper customers sharing all listed parts, but it's more effective leaving this work to dictionaries and use AutoFilter() for the final copy/paste part. like follows:
Option Explicit
Sub main()
Dim custDict As Scripting.Dictionary, partDict As Scripting.Dictionary
Dim cust As Variant, part As Variant
Dim parts As String
Dim okCust As Boolean
With Worksheets("MyListSheetName")
Set partDict = GetList(.Range("A1", .Cells(.Rows.count, 1).End(xlUp)))
End With
With Worksheets("MyDataSheetName")
With .Range("Z1", .Cells(.Rows.count, 1).End(xlUp)) '<--| reference its A to Z columns cells from row 1 down to column A last not empty cell
Set custDict = GetList(.Resize(.Rows.count, 1).Offset(1))
For Each cust In custDict.Keys
parts = custDict(cust) & "|"
For Each part In partDict.Keys
okCust = InStr(parts, "|" & part & "|") > 0
If Not okCust Then Exit For
Next part
If okCust Then
.AutoFilter field:=1, Criteria1:=cust
With .Resize(.Rows.count - 1).Offset(1).SpecialCells(xlCellTypeVisible) '<--| reference filtered cells, skipping headers
.Copy Destination:=GetSheet(CStr(cust)).Range("A1")
End With
End If
Next cust
End With
.AutoFilterMode = False
.Activate
End With
End Sub
Function GetList(rng As Range) As Scripting.Dictionary
Dim dict As New Scripting.Dictionary
Dim cell As Range
For Each cell In rng.Cells
dict(cell.Value) = dict(cell.Value) & "|" & cell.Offset(, 1)
Next cell
Set GetList = dict
End Function
Function GetSheet(shtName As String) As Worksheet
On Error Resume Next
Set GetSheet = Worksheets(shtName)
If GetSheet Is Nothing Then
Set GetSheet = Worksheets.Add
GetSheet.Name = shtName
Else
GetSheet.UsedRange.ClearContents
End If
End Function
I am working with a spreadsheet to produce a report. The data will vary depending on the department for which I am reporting. I need to select the records in column A that are the result of a filter and paste them in column B, once pasted I need to clear the cells in column A then remove the filter. I have been able to accommodate the variable criteria for the filter; however, my problem is with selecting the variable range. The data to be selected will never start in cell A2, any cell after that is fair game. How do I select a range that varies? How do I have the User interact with the macro to select the cells?
This works for me to filter by all my variables.
Cells.Select
Selection.AutoFilter
ActiveSheet.Range("$A$1:$F$65000").AutoFilter Field:=1, Criteria1:=Array( _
"1000", "1001", "1005", "ZBIL", "1002", "1003", "1004", "1006", "1007", "1008", "1009", "AOMS", "ASPS", "NATL", "ZCON", "ZREP"), Operator:=xlFilterValues
On Error Resume Next
I am using the following to select the range, the first line works to select the data to be copied (although it still selects the cell A1 and I would prefer not to have that cell selected). The second line returns an error "Object doesn't support this property or method. I have tried range select ToRight however I end up with the entire sheet selected.
Range(ActiveCell, ActiveCell.End(xlDown)).Select
Selection(Selection, Selection.xlToRight).Select
Selection.FillRight
I appreciate any assistance that is available.
It might not be the most efficient solution, but you can loop through all the cells/rows and check if the filter hid them:
Dim lastrow As Integer
Dim i As Integer
With ActiveSheet
lastrow = .Cells(Rows.Count, 1).End(xlUp).Row
For i = 3 To lastrow
If .Rows(i).Hidden = False Then
.Cells(i, 2).Value = .Cells(i, 1).Value
.Cells(i, 1).Value = ""
End If
Next i
End With