Loop to search and print unique value from range - vba

I have a list of values, and in a table, I have those same values spread out.
I need some sort of loop that can search the 1x20 list and print the first value that is not already in the table, without having to write numerous countif() statements. Is there a way to do this faster?

Sure you need a loop of a range of cells and test if value exists. You'd need to post more of your code to give a specific example but this should get you started:
Sub LoopExampleUsingRange()
Dim aCell As Range
For Each aCell In ActiveSheet.Range("A1:A20").Cells
If InStr(1, "SOME TEXT/table/OR A CELL VALUE TO S", aCell.Value) Then
'if it exists put here
'Perhaps do nothing?
Else
'if doesn't exist put some code here.
End If
Next aCell
End Sub

Related

VBA checking no results after filtering a table

I have the following table:
And the following code (that filters this table):
Sub testFilter()
Dim tbl As ListObject
Dim filteredRange As Range
Set tbl = Sheet1.ListObjects("testTbl")
tbl.Range.AutoFilter Field:=2, Criteria1:=Array("a", "b")
On Error Resume Next
Set filteredRange = tbl.ListColumns("status").DataBodyRange.SpecialCells(xlVisible)
On Error GoTo 0
If filteredRange Is Nothing Then
'do something
Else
Debug.Print filteredRange.Address
End If
End Sub
I expect filteredRange to be nothing.
But it's not nothing, and the address it prints is:
$1:$1,$3:$1048576
which is basically the entire sheet beside the one row I have in the table.
What am I doing wrong?
I need the ability to detect that the filter gave no results.
I can reproduce this behavior, but only if the table has only one row of data. As soon as a second row is added, it behaves as expected. I cannot find an explanation for that, could be one of the quirks of Excel.
If it can really happen with your data that the table has only one row, you could maybe use the workaround
If filteredRange Is Nothing Or (tbl.Range.Rows.Count = 2 And tbl.Range.Rows(2).Hidden) Then
One remark: I think your filter-statement needs a parameter Operator:=xlFilterValues if you pass an array of values:
tbl.Range.AutoFilter Field:=2, Criteria1:=Array("a", "b"), Operator:=xlFilterValues

How to specify a Column for VBA's Autofilter function by name rather than by its index?

I am new to VBA and trying to autofilter a column range. The column is named "Vlookup" and sits at index position 27.
rData.AutoFilter field:=27, Criteria1:="Class" ' filter criterion
In order to make this dynamic, I need to be able to filter according to column name rather than column index.
However, when I do
rData.AutoFilter field:=Application.Match("Vlookup", Selection.Rows(1), 0), Criteria1:="Class" ' filter criterion
I yield
Runtime Error '424' - Object Required
How to correctly Autofilter by column name in VBA?
Not sure what option you went with but we had a similar issue and we discovered that it is as easy as using a table for your data then use Field:=Listobject.ListColumns("Column Name").Index. This way your solution is dynamic.
Set rData = Workbooks("Workbook Name").Worksheets("Sheet Name").Listobjects("Table Name")
rData.DataBodyRange.AutoFilter field:=rData.ListColumns("Vlookup").Index, Criteria1:="Class"
You can use helper UDF which will return column's index:
Function GetIndex(colName As String)
GetIndex = WorksheetFunction.Match(colName, ActiveSheet.AutoFilter.Range.Rows(1), 0)
End Function
UPD
You can substitute ActiveSheet with your sheet.
You can use the Find function to find "Vlookup" in the header row, and then retrieve the numeric value of the Column.
Note: there's no need to use Selection, instead fully qualify your Rows(1) with your rData sheet object (use the With rData statement).
See code and comments below:
Dim FindRng As Range
Dim FiltCol As Long
With rData
Set FindRng = .Rows(1).Find(what:="Vlookup")
If Not FindRng Is Nothing Then ' Find was successful
FiltCol = FindRng.Column ' get the column number where "Vlookup" was found
Else ' find unable to find "Vlookup"
MsgBox "Find Error!"
Exit Sub
End If
.AutoFilter Field:=FiltCol, Criteria1:="Class" ' filter criterion
End With

Manipulating Excel spreadsheet, removing rows based on values in a column and then removing more rows based on values in another column

I have a rather complicated problem.
I have a log file that when put into excel the column "I" contains event IDs, and the column J contains a custom key that keeps a particular even grouped.
All i want to do is remove any rows that do not contain the value of say 102 in the event id column.
And THEN i need to check the custom key (column J) and remove rows that are duplicates since any duplicates will falsely show other statistics i want.
I have gotten as far as being able to retrieve the values from the columns using com objects and .entirecolumn cell value etc, but I am completely stumped as to how i can piece together a solid way to remove rows. I could not figure out how to get the row for each value.
To give a bit more clarity this is my thought process on what i need to do:
If cell value in Column I does not = 102 Then delete the row that cell contains.
Repeat for all rows in spreadsheet.
And THEN-
Read every cell in column J and remove all rows containing duplicates based on the values in column J.
Save spreadsheet.
Can any kind persons help me?
Additional Info:
Column I holds a string that is an event id number e.g = 1029
Column J holds a string that is a mix of numbers and letters = 1ASER0X3NEX0S
Ellz, I do agree with Macro Man in that your tags are misleading and, more importantly, I did indeed need to know the details of Column J.
However, I got so sick of rude posts today and yours was polite and respectful so I've pasted some code below that will do the trick ... provided Column J can be a string (the details of which you haven't given us ... see what Macro Man's getting at?).
There are many ways to test for duplicates. One is to try and add a unique key to a collection and see if it throws an error. Many wouldn't like that philosophy but it seemed to be okay for you because it also gives you a collection of all the unique (ie remaining) keys in Column J.
Sub Delete102sAndDuplicates()
Dim ws As Worksheet
Dim uniques As Collection
Dim rng As Range
Dim rowPair As Range
Dim iCell As Range
Dim jCell As Range
Dim delRows As Range
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set rng = Intersect(ws.UsedRange, ws.Range("I:J"))
Set uniques = New Collection
For Each rowPair In rng.Rows
Set iCell = rowPair.Cells(, 1)
Set jCell = rowPair.Cells(, 2)
On Error Resume Next
uniques.Add jCell.Value2, jCell.Text
If Err = 457 Or iCell.Value2 = 102 Then
On Error GoTo 0
If delRows Is Nothing Then
Set delRows = rowPair.EntireRow
Else
Set delRows = Union(delRows, rowPair.EntireRow)
End If
End If
Next
If Not delRows is Nothing then
MsgBox delRows.Address(False, False) & " deleted."
delRows.Delete
End If
End Sub
There are a number of ways in which this can be done, and which is best will depend on how frequently you perform this task and whether you want to have it fully automated. Since you've tagged your question with VBA I assume you'll be happy with a VBA-based answer:
Sub removeValues()
Range("I1").Select 'Start at the top of the I column
'We are going to go down the column until we hit an empty row
Do Until IsEmpty(ActiveCell.Value) = True
If ActiveCell.Value <> 102 Then
ActiveCell.EntireRow.Delete 'Then delete the row
Else
ActiveCell.Offset(1).Select 'Select the cell below
End If
Loop
'Now we have removed all non-102 values from the column, let`s remove the duplicates from the J column
Range("A:J").RemoveDuplicates Columns:=10, Header:=xlNo
End Sub
The key line there is Range("A:J").RemoveDuplicates. It will remove rows from the range you specify according to duplicates it finds in the column you specify. In that case, it will remove items from the A-J columns based on duplicates in column 10 (which is J). If your data extends beyond the J column, then you'll need to replace "A:J" with the appropriate range. Note that the Columns value is relative to the index of the first column, so while the J column is 10 when that range starts at A (1), it would be 2 for example if the range were only I:J. Does that make sense?
(Note: Using ActiveCell is not really best practice, but it's the method that most obviously translates to what you were trying to do and as it seems you're new to VBA I thought it would be the easiest to understand).

How to delete row based on cell value

I have a worksheet, I need to delete rows based on cell value ..
Cells to check are in Column A ..
If cell contains "-" .. Delete Row
I can't find a way to do this .. I open a workbook, copy all contents to another workbook, then delete entire rows and columns, but there are specific rows that has to be removed based on cell value.
Need Help Here.
UPDATE
Sample of Data I have
The easiest way to do this would be to use a filter.
You can either filter for any cells in column A that don't have a "-" and copy / paste, or (my more preferred method) filter for all cells that do have a "-" and then select all and delete - Once you remove the filter, you're left with what you need.
Hope this helps.
The screenshot was very helpful - the following code will do the job (assuming data is located in column A starting A1):
Sub RemoveRows()
Dim i As Long
i = 1
Do While i <= ThisWorkbook.ActiveSheet.Range("A1").CurrentRegion.Rows.Count
If InStr(1, ThisWorkbook.ActiveSheet.Cells(i, 1).Text, "-", vbTextCompare) > 0 Then
ThisWorkbook.ActiveSheet.Cells(i, 1).EntireRow.Delete
Else
i = i + 1
End If
Loop
End Sub
Sample file is shared: https://www.dropbox.com/s/2vhq6vw7ov7ssya/RemoweDashRows.xlsm
You could copy down a formula like the following in a new column...
=IF(ISNUMBER(FIND("-",A1)),1,0)
... then sort on that column, highlight all the rows where the value is 1 and delete them.
if you want to delete rows based on some specific cell value.
let suppose we have a file containing 10000 rows, and a fields having value of NULL.
and based on that null value want to delete all those rows and records.
here are some simple tip.
First open up Find Replace dialog, and on Replace tab, make all those cell containing NULL values with Blank.
then press F5 and select the Blank option, now right click on the active sheet, and select delete, then option for Entire row.
it will delete all those rows based on cell value of containing word NULL.
If you're file isn't too big you can always sort by the column that has the - and once they're all together just highlight and delete. Then re-sort back to what you want.
You can loop through each the cells in your range and use the InStr function to check if a cell contains a string, in your case; a hyphen.
Sub DeleteRowsWithHyphen()
Dim rng As Range
For Each rng In Range("A2:A10") 'Range of values to loop through
If InStr(1, rng.Value, "-") > 0 Then 'InStr returns an integer of the position, if above 0 - It contains the string
rng.Delete
End If
Next rng
End Sub
This is the autofilter macro you could base a function off of:
Selection.AutoFilter
ActiveSheet.Range("$A$1:$A$10").AutoFilter Field:=1, Criteria1:="=*-*", Operator:=xlAnd
Selection.AutoFilter
I use this autofilter function to delete matching rows:
Public Sub FindDelete(sCol As String, vSearch As Variant)
'Simple find and Delete
Dim lLastRow As Integer
Dim rng As Range
Dim rngDelete As Range
Range(sCol & 1).Select
[2:2].Insert
Range(sCol & 2) = "temp"
With ActiveSheet
.usedrange
lLastRow = .Cells.SpecialCells(xlCellTypeLastCell).Row
Set rng = Range(sCol & 2, Cells(lLastRow, sCol))
rng.AutoFilter Field:=1, Criteria1:=vSearch, Operator:=xlAnd
Set rngDelete = rng.SpecialCells(xlCellTypeVisible)
rng.AutoFilter
rngDelete.EntireRow.Delete
.usedrange
End With
End Sub
call it like:
call FindDelete "A", "=*-*"
It's saved me a lot of work. Good luck!

Copy/Paste cells next to cells that have certain string

I am trying to look up cells in a certain column that have a string (e.g. Names), copy the corresponding cells in the column to its right (i.e. offset(0,1) ), then paste it to a column in a different sheet. I have the following code to find the range variable that I want. However, I can't select it from a different sheet!
When I use Sheets(1).MyRange.Copy, it doesn't accept it. Am I referring to the range in a wrong way? What am I doing wrong?
Here's code that I use to get MyRange:
Option Explicit
Sub SelectByValue(Rng1 As Range, Value As Double)
Dim MyRange As Range
Dim Cell As Object
'Check every cell in the range for matching criteria.
For Each Cell In Rng1
If Cell.Value = Value Then
If MyRange Is Nothing Then
Set MyRange = Range(Cell.Address)
Else
Set MyRange = Union(MyRange, Range(Cell.Address))
End If
End If
Next
End Sub
Sub CallSelectByValue()
'Call the macro and pass all the required variables to it.
'In the line below, change the Range, Minimum Value, and Maximum Value as needed
Call SelectByValue(Sheets(1).Range("A1:A20"), "Tom")
End Sub
One More Question: Rather than specifying the exact range to look at (e.g. "A1:A20"), I would LOVE to look at all of column A. But I don't want to use ("A:A") so it wouldn't look at all rows of A. Isn't there a method to look only in cells that have entries in column A?
Thank you VERY much.
Al
You only need MyRange.Copy.
To restrict only to cells in column A which might have values, you could use
With Sheet1
Set rngToSearch = Application.Intersect(.Columns(1), .UsedRange)
End With
...or maybe look at .SpecialsCells()