Cannot remove duplicates from range - vba

I have an excel table with several columns two of which I am interested in. What I am trying to do is filter the first column with a specific criterion and then copy the visible values from the other column into a range object. After that I need to remove duplicates. The problem is I get an error. Here's the code. There are a lot of duplicates. Please tell me what's wrong or suggest a better way to achieve the task I'm trying to do.
Sub Begin()
Dim tbl As ListObject
Set tbl = Worksheets("Sheet1").ListObjects("Table1")
WorkSheet.AutoFilterMode = False
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
Dim rng1 As Range
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
rng1.RemoveDuplicates Columns:=1, Header:=xlNo
MsgBox rng1.Count
End Sub

You're off to a great start, but unfortunately as #siddharth-rout pointed out .RemoveDuplicates will not work on a non-contiguous range.
In this case, to collect the all the unique cell values from the "TGT CELL NAME" column, you could use a collection (MSDN link):
Sub Begin()
Dim tbl As ListObject
Dim rng1 As Range, RngIdx As Range
Dim MySheet As Worksheet
Dim UniqueTGTCells As Collection
Set MySheet = ThisWorkbook.Worksheets("Sheet1")
Set tbl = MySheet.ListObjects("Table1")
'only turn off auto filter mode if it's already set to true
If MySheet.AutoFilterMode = True Then
MySheet.AutoFilterMode = False
End If
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
'populate the collection object
Set UniqueTGTCells = New Collection
For Each RngIdx In rng1
On Error Resume Next
UniqueTGTCells.Add LCase(CStr(RngIdx.Value)), LCase(CStr(RngIdx.Value))
On Error GoTo 0
Next RngIdx
'message the size of the collection
MsgBox UniqueTGTCells.Count
End Sub
Here are our message boxes:

My own solution to this old post below, in case anybody struggle again with that.
Note that I translated my working code into the posted one without testing, but I guess the idea is simple enough to be applied anyway.
Sub Begin()
Dim tbl As ListObject
Set tbl = Worksheets("Sheet1").ListObjects("Table1")
WorkSheet.AutoFilterMode = False
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
' Sort to make sure filtered view will be contiguous
tbl.range.sort Key1:=tbl.range.cells(1,8), Order1:=xlAscending, Header:=xlYes
Dim rng1 As Range
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
' Using Areas(1) does the trick (there is only 1 area - no gaps - thanks to sorting)
rng1.Areas(1).RemoveDuplicates Columns:=1, Header:=xlNo
MsgBox rng1.Count
End Sub

Related

VBA Includes empty cells in table formatting

Very new to VBA.
What I am trying to do:
1) Copy sheet from (source) workbook to active (master) workbook
2) Delete unnecessary columns of the copied data in the master workbook
3) Select cells with data in the master workbook and format as table (this is where I am stuck)
Sub first_sub()
'Open user Raw Data workbook
Workbooks.Open Filename:= _
"C:\Users\" & Environ("UserName") & "\Downloads\File.xls"
'Copy user Raw Data sheet to Data Master sheet
Workbooks("File.xls").Sheets("Records").Copy _
Before:=Workbooks("Macro Main.xlsm").Sheets(1)
'Close user Raw Data
Workbooks("File.xls").Close
End Sub
Sub Format()
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Clear
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Delete
End Sub
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub
The problem is in point 3. For some reasons, VBA selects columns up to "AM", even though I deleted them in previous sub, and as a result - I have the table full of empty columns all the way up to AM. How to solve this? Thank you in advance.
Check how .SpecialCells(xlLastCell) works: Range.SpecialCells Method (Excel)
I think your range variable rng is referencing from range Range("A1") to the last used cell in the column range AM
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Try adding this line after to check if the range is actually targeting your desired range:
rng.select
To solve this problem you can try:
Set rng = Range("A1").CurrentRegion
Or finding the last cell in column A...
Code:
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range("A1").CurrentRegion
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub

Move selected range over one column with VBA in Excel 2016

I need to be able te
Find a value in column A
Select that value and everything above it
Offset all those values over one column
The below code does just that - however, I am trying to speed up the code execution, and copy and paste actions slow it down. Is there a way to accomplish this without the cut/paste? I'd like to stick with VBA (vice formula) since this is part of a larger procedure.
Thanks!
Sub FindValueAndAboveThenMoveOver ()
Dim sht1 as Worksheet
Set sht1 = Sheets("Convert")
sht1.Columns("A:A").Find("XXXX"), LookIn:=xlValues).Select
Range(ActiveCell.Offset(0, 0), "A1").Select
Selection.Cut
Range("B1").Select
ActiveSheet.Paste
End Sub
Nothing wrong with Cut and Paste, but you can avoid it, and avoiding Select will speed things up. Plus you should check first that you have found something to avoid an error.
Sub FindValueAndAboveThenMoveOver()
Dim sht1 As Worksheet, r As Range
Set sht1 = Sheets("Convert")
Set r = sht1.Columns("A:A").Find("XXXX", LookIn:=xlValues)
If Not r Is Nothing Then
'should add sheet references here too
With Range("A1").Resize(r.Row)
Range("B1").Resize(r.Row).Value = .Value
.ClearContents
End With
End If
End Sub
This might be slightly faster:
Sub FindValueAndAboveThenMoveOver()
Dim sht1 As Worksheet, r As Range
Set sht1 = Sheets("Convert")
With sht1
Set r = Range(.Range("A1"), .Columns("A:A").Find("XXXX", LookIn:=xlValues))
End With
r.Offset(0, 1).Value = r.Value
r.Clear
End Sub

How to filter the table and paste the value in another sheet in Excel VBA

I would like to get value from the user and filter the table. I am filtering Column A (EP Number). Then copy the entire row to another sheet. If there is more than one row, copy both the rows and paste in different sheet.
I used the code below. Its not working and showing Type mismatch error.
Private Sub CommandButton1_Click()
Dim str1 As String
str1 = Application.InputBox("Enter EP Number")
If CStr(str1) Then
Sheets("Sheet2").Select
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:= _
"str1", Operator:=xlAnd
Range("A10:E10").Select
Selection.Copy
Sheets("Sheet4").Select
Range("Table2").Select
ActiveSheet.Paste
Range("J7").Select
Else
MsgBox ("Wrong EP")
End If
End Sub
First, since you are trying to check the AutoFilter Criteria with your variable str1, you need to take it outside the double-quote ", it need to be Criteria1:=str1.
Second, avoid all the unecessary Select and ActiveSheet, instead use fully qualifed objects.
You can use the Dim Tbl As ListObject , later set it explicitly by Set Tbl = Sheets("Sheet2").ListObjects("Table1").
Code
Option Explicit
Private Sub CommandButton1_Click()
Dim str1 As String
Dim Tbl As ListObject
Dim FiltRng As Range
Dim RngArea As Range
' set the List Object "Table1"
Set Tbl = Sheets("Sheet2").ListObjects("Table1")
str1 = Application.InputBox("Enter EP Number")
Tbl.Range.AutoFilter field:=1, Criteria1:=str1
' when using Filtered range, the range can be splitted to several areas >> loop through each one of them
For Each RngArea In Tbl.Range.SpecialCells(xlCellTypeVisible).Rows
' don't use the Header Row
If RngArea.Row > 1 Then
If Not FiltRng Is Nothing Then
Set FiltRng = Application.Union(FiltRng, RngArea)
Else
Set FiltRng = RngArea
End If
End If
Next RngArea
If Not FiltRng Is Nothing Then ' filter range is not empty
FiltRng.Copy
Else
MsgBox "No Records match in the Table", vbCritical
Exit Sub
End If
' do here your paste thing
End Sub

I'm getting Subscript out of range (Error 9)

the below code is not working I'm getting Subscript out of range (Error 9)
Sub advnextract()
Sheets.Add(Before:=ActiveSheet).Name = "Resultado"
Set extractto = ThisWorkbook.Worksheets("Resultado").Range("A5:G5")
Selection.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=Range( _
"J1:J2"), CopyToRange:=extractto, Unique:=False
End Sub
Need help this is supposed to run a advanced filter and paste the result in the newly created sheet, the original table in the selection has data ranging from A1 to G11
As stated in the comments, the creation of a worksheet causes that to gain focus. Also you need to copy the titles to the sheet so excel knows where to put the values:
Sub advnextract()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim rng As Range
Dim extractto as range
Set rng = Selection 'It is better to set an actual range instead of Selection.
'Also Selection must have at least 7 columns or this will error.
'It also needs to include the column headers in the Selection.
Sheets.Add(Before:=ActiveSheet).Name = "Resultado"
Set extractto = ThisWorkbook.Worksheets("Resultado").Range("A5:G5")
extractto.Value = rng.Rows(1).Value
rng.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=ws.Range( _
"J1:J2"), CopyToRange:=extractto, Unique:=False
End Sub
After trial and error and some insight into some logic here is the final result
Sub advnextract()
Dim rng As Range
Set rng = Selection
Sheets.Add(Before:=Sheets("Hoja1")).Name = "Resultado"
rng.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=Sheets("Hoja1").Range("J1:J2"), _
CopyToRange:=Sheets("Resultado").Range("A1"), Unique:=False
Sheets("Resultado").Activate
Columns("A:G").EntireColumn.AutoFit
Range("A1").Select
End Sub
I know it can be improved to be more efficient but for some reason I can't explain this is the code that works for me.

Iterate on autofiltered visible cells on VBA

I'm trying to do something weird, and it's maybe not the only way, and it's probably the wrong one. I want to iterate on the visible cells (which is the result of the AutoFilter function of VBA).
Here's what I've done before, and it works, but not how I want :
Sheets("MySheet").Range("$A$3:$AI$10191").AutoFilter Field:=12, Criteria1:=myList, Operator:=xlFilterValues . myList is a list of String, like this : Dim myList() as String
Currently, this does not fit with what I want : I do not want this to take the blank cells, and I also want the myList() content be taken approximativly (something like ""&myList&"").
To do that, I tried one simple line of code and it works :
Sheets("MySheet").Range("$A$3:$AI$10191").AutoFilter Field:=12, Criteria1:="*"&myList(0)&"*", Operator:=xlFilterValues
My problem is : I want to do that for all the elements of my list. I've been thinking about iterating through my list (myList) but everytime I'm doing a new iteration, it simply does not take the result of the previous iteration . In reality, I just want to filter on the "already filtered" rows...
I already tried the method with .SpecialCells(xlCellTypeVisible) but it takes all the cells, and not only the visible one.... (here's the full code with visible cells : Sheets("MySheet").Range("$A$3:$AI$10191").SpecialCells(xlCellTypeVisible).AutoFilter Field:=12, Criteria1:="*"&myList(0)&"*", Operator:=xlFilterValues)
I've been thinking on something like that :
For i =0 to UBound(myList)
Sheets("MySheet").Range("$A$3:$AI$10191").SpecialCells(xlCellTypeVisible).AutoFilter Field:=12, Criteria1:="*"&myList(i)&"*", Operator:=xlFilterValues
Next i
But it just filters following the last .AutoFilter rule. (it filters on i=UBound(myList) , because each .AutoFilter is erasing the job of the previous one... )
If you have any ideas... Thanks, Clément.
To try the Advanced Filter, you can give this a try.
Tweak it as required...
Sub AdvancedFilter()
Dim wsData As Worksheet, wsCriteria As Worksheet
Dim myList() As String
Dim i As Long, lr As Long
Dim Rng As Range, Cell As Range
Application.ScreenUpdating = False
Set wsData = Sheets("MySheet")
If wsData.FilterMode Then wsData.ShowAllData
lr = wsData.UsedRange.Rows.Count
On Error Resume Next
Set wsCriteria = Sheets("Criteria")
wsCriteria.Cells.Clear
On Error GoTo 0
If wsCriteria Is Nothing Then
Sheets.Add.Name = "Criteria"
Set wsCriteria = ActiveSheet
End If
'Assuming myList has already been populated
'Writing the column header (column 12) on Criteria Sheet in A1
wsCriteria.Cells(1, 1) = wsData.Cells(1, 12)
'Adding wild card to each element in myList
For i = 1 To UBound(myList)
myList(i) = "*" & myList(i) & "*"
Next i
'Writing myList on Criteria Sheet
wsCriteria.Range("A2").Resize(UBound(myList)).Value = Application.Transpose(myList)
'Using Advanced Filter on Data Sheet with Criteria on Criteria Sheet
wsData.Range("A1").CurrentRegion.AdvancedFilter xlFilterInPlace, wsCriteria.Range("A1").CurrentRegion
'Deleting the Criteria Sheet as it is not required now
Application.DisplayAlerts = False
wsCriteria.Delete
Application.DisplayAlerts = True
'Setting Rng as visible cells in column A
On Error Resume Next
Set Rng = wsData.Range("A2:A" & lr).SpecialCells(xlCellTypeVisible)
If Not Rng Is Nothing Then
For Each Cell In Rng
'Do your stuff here with visible range
Next Cell
End If
If wsData.FilterMode Then wsData.ShowAllData
Application.ScreenUpdating = True
End Sub