Search for multiple values and select - vba

So far, I have an excel file as such
http://i.stack.imgur.com/zX3xC.png
My problem is that I want to be able to input a number after having the search button pressed and an Input box appears, With the number in the search bar for all numbers that match in the spreadsheet to be selected.
Also as as addition to be able to put in a few numbers (40, 21, 33 separated by commas)
My current code is:
Sub SEARCH_Click()
Dim sh1 As Sheet1
Dim rng As Range
Dim uname As String
Set sh1 = Sheet1: uname = InputBox("Input")
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
With sh1
.AutoFilterMode = False
Set rng = .Range("A4", .Range("A" & .Rows.Count).End(xlUp))
On Error Resume Next
rng.SpecialCells(xlCellTypeVisible).Select
If Err.number <> 0 Then MsgBox "Data not found" _
Else MsgBox "All matching data has been selected"
.AutoFilterMode = False
On Error GoTo 0
End With
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
End Sub
I am fairly new to coding so a lot of this has come from internet research etc.

Abandon your AutoFilter method in favor of a Range.Find method. While ultimately possible with a series of .AutoFilters applied to each column, simply collecting the results from a .Find operation with the Union method makes more sense.
Private Sub CommandButton1_Click()
Dim uname As String, sh1 As Worksheet '<~~ there is no var type called Sheet1
Dim v As Long, fnd As Range, rng As Range, addr As String, vals As Variant
Set sh1 = Sheet4
uname = InputBox("Search for...")
vals = Split(Replace(uname, Chr(32), vbNullString) & Chr(44), Chr(44))
ReDim Preserve vals(UBound(vals) - 1)
With sh1
For v = LBound(vals) To UBound(vals)
If IsNumeric(vals(v)) Then vals(v) = Val(vals(v))
Set fnd = .Cells.Find(What:=vals(v), LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchFormat:=False)
If Not fnd Is Nothing Then
addr = fnd.Address
Do
If rng Is Nothing Then
Set rng = fnd
Else
Set rng = Union(rng, fnd)
End If
Set fnd = .Cells.FindNext(after:=fnd)
Loop Until addr = fnd.Address
End If
addr = vbNullString
Set fnd = Nothing
Next v
If Not rng Is Nothing Then rng.Select
End With
End Sub
It is not clear what actions you want to perform after the Range .Select¹ method has been applied. I would suggest that a simple With ... End With statement woudl allow you to continue working on the rng discontiguous Range object without actually selecting it at all.
    
¹ See How to avoid using Select in Excel VBA macros for more methods on getting away from relying on select and activate to accomplish your goals.

Related

Delete columns based on header value VBA

I am trying to delete columns that contain the text "Title" from all the Worksheets. (It could be Title A, Title B, etc.)
I wrote the below, but it's not working... Please enlighten me.
Dim wsh As Worksheet
Dim A As Range
For Each wsh In ActiveWorkbook.Worksheets
Do
Set A = Rows(1).Find(What:="Title", LookIn:=xlValues, lookat:=xlPart)
If A Is Nothing Then Exit Do
A.EntireColumn.Delete
Loop
Next wsh
Since you are looking for "Title A" (as well for only "Title") , you can use the Find in 2 ways:
Add the * wild-card to the searched string, and at the third parameter have xlWhole Find(What:="Title*", LookIn:=xlValues, lookat:=xlWhole)
Don't use the * wild-card, and use xlPart .Find(What:="Title", LookIn:=xlValues, lookat:=xlPart)
Code
Option Explicit
Sub RemoveTitle()
Dim wsh As Worksheet
Dim A As Range
For Each wsh In ActiveWorkbook.Worksheets
Do
Set A = wsh.Rows(1).Find(What:="Title", LookIn:=xlValues, lookat:=xlPart)
If Not A Is Nothing Then
A.EntireColumn.Delete
End If
Loop While Not A Is Nothing
Next wsh
End Sub
You are not qualifying your range with a sheet so only the active sheet is searched
Sub x()
Dim wsh As Worksheet
Dim A As Range
For Each wsh In ActiveWorkbook.Worksheets
Do
Set A = wsh.Rows(1).Find(What:="Title", LookIn:=xlValues, lookat:=xlPart)
If A Is Nothing Then Exit Do
A.EntireColumn.Delete
Loop
Next wsh
End Sub
You need to specify the sheet in which you use Find
And add * (wildcard) to include all possibilities
Dim wsh As Worksheet
Dim A As Range
For Each wsh In ActiveWorkbook.Worksheets
Do
Set A = wsh.Rows(1).Find(What:="Title*", LookIn:=xlValues, lookat:=xlPart)
If A Is Nothing Then Exit Do
A.EntireColumn.Delete
Loop
Next wsh
you may want to delete all columns in one shot
Option Explicit
Sub main()
Dim wsh As Worksheet
Dim A As Range, foundTitle As Range
Dim firstAddress As String
For Each wsh In ActiveWorkbook.Worksheets
With wsh.Range("A1", wsh.Cells(1, wsh.Cells.Columns.Count).End(xlToLeft))
Set foundTitle = .Offset(1).Resize(1, 1)
Set A = .Find(What:="Title", LookIn:=xlValues, lookat:=xlPart)
If Not A Is Nothing Then
firstAddress = A.Address
Do
Set foundTitle = Union(foundTitle, A)
Set A = .FindNext(A)
Loop While A.Address <> firstAddress
End If
Set foundTitle = Intersect(foundTitle, .Cells)
If Not foundTitle Is Nothing Then foundTitle.EntireColumn.Delete
End With
Next wsh
End Sub

remove all sheets till a given set of names using VBA

I want to remove all sheets in the current workbook exception the list in {A2,A3, ... } and the sheet with name Summary.
I wrote the following code
Dim MyCell As Range, MyRange As Range
Set MyRange = Sheets("Summary").Range("A2")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wbook = ActiveWorkbook
For Each xWs In wbook.Worksheets
For Each MyCell In MyRange
If xWs.Name <> MyCell.Value And xWs.Name <> "Summary" Then
xWs.Delete
End If
Next MyCell
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
but I get an run time error which I do not know what it is.
Then, I tried to run line by line: in the first loop over "xWs.Name= Summary" there is no problem first for the second sheet I get an error at
If xWs.Name <> MyCell.Value And xWs.Name <> "Summary" Then
I know that this code is not efficient at all, because if a name matches it is still running till the end of set of names. However, I did not know how I can compare tow sets in VBA in a efficient way.
One can see in the the list of names in A-column.
You need to approach it a little different, you need to loop though the Range on every Sheet, once you have a match you need to raise a flag not to delete this Sheet.
Try the code below:
Sub DeleteSelectedSheets()
Dim MyCell As Range, MyRange As Range
Dim wbook As Workbook, xWs As Worksheet
Dim DeleteSheetFlag As Boolean
Set MyRange = Sheets("Summary").Range("A2")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set wbook = ActiveWorkbook
For Each xWs In wbook.Worksheets
DeleteSheetFlag = True
For Each MyCell In MyRange
Select Case xWs.Name
Case MyCell.Value, "Summary"
DeleteSheetFlag = False
Exit For
End Select
Next MyCell
If DeleteSheetFlag Then
xWs.Delete
End If
Next xWs
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

Code to allow user make range selection to search list in another workbook and return cell value

Info
Workbook A: Has a master worksheet with a list of items, but the values are arranged in month columns
Workbook B: I have two sheets with different list of items I want to use to search Workbook A and return the current or specific month I need.
Note: Workbook B columns is offset, so we may need to account for this.
The code I have so far:
Sub Button()
Dim OpenFileName As String
Dim MyWB As Workbook, wb As Workbook
Dim aRange As Range
'Excel titled, "MODs", contains this module
Set MyWB = ThisWorkbook
'Ignore possible messages on a excel that has links
Application.AskToUpdateLinks = False
Application.DisplayAlerts = False
'Select and Open workbook
OpenFileName = Application.GetOpenFilename '("clients saved spreadsheet,*.xlsb")
If OpenFileName = "False" Then Exit Sub
Set wb = Workbooks.Open(OpenFileName)
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
If MsgBox("Please select list range to search.", vbExclamation, "Search List") = vbOK Then
On Error Resume Next
Set aRange = Application.InputBox(prompt:="Enter range", Type:=8)
If aRange Is Nothing Then
MsgBox "Operation Cancelled"
Else
aRange.Select
End If
End If
End Sub
I might might be making this harder than I should be, so I am open to suggestions. I can't seem to find the right find function to use my selected range list and target the newly open workbook with the specific master worksheet (something similar to a vlookup).
Version 2: with a set range but I'm still getting not value returns
Sub Button()
Dim OpenFileName As String
Dim MyWB As Workbook, wb As Workbook
Dim MyWs As Worksheet, ws As Worksheet
Dim aRange As Range
'This line of code turns off the screen updates which make the macro run much faster.
'Application.ScreenUpdating = False
'Excel titled, "MODs", contains this module
Set MyWB = ThisWorkbook
Set MyWs = MyWB.Sheets("Sheet")
'Ignore possible messages on a excel that has links
Application.AskToUpdateLinks = False
Application.DisplayAlerts = False
'Select and Open workbook
OpenFileName = Application.GetOpenFilename '("clients saved spreadsheet,*.xlsb")
If OpenFileName = "False" Then Exit Sub
Set wb = Workbooks.Open(OpenFileName)
On Error Resume Next
Set ws = Application.InputBox("Select a cell on the key sheet.", Type:=8).Parent
On Error GoTo 0
If ws Is Nothing Then
MsgBox "cancelled"
Else
MsgBox "You selected sheet " & ws.Name
End If
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
With MyWs
For Each aCell In .Range("A1:A10" & LastRow)
If Len(Trim(.Range("A19" & aCell.Row).Value)) <> 0 Then
.Cells(aCell.Row, 15) = Application.WorksheetFunction.VLookup( _
aCell.Value, ws.Range("A1:C18"), 2, 0)
End If
Next aCell
End With
'wb.Close (False)
'If MsgBox("Please select list range to search.", vbExclamation, "Search List") = vbOK Then
'On Error Resume Next
'Set aRange = Application.InputBox(prompt:="Enter range", Type:=8)
'If aRange Is Nothing Then
'MsgBox "Operation Cancelled"
'Else
'aRange.Select
'End If
'End If
'Return to default setting of screen updating.
'Application.ScreenUpdating = True
End Sub
I think the problem I'm running into is this code:
With MyWs
For Each aCell In .Range("A1:A10" & LastRow)
If Len(Trim(.Range("A19" & aCell.Row).Value)) <> 0 Then
.Cells(aCell.Row, 15) = Application.WorksheetFunction.VLookup( _
aCell.Value, ws.Range("A1:C18"), 2, 0)
begin declaringaCell as Range and lastRow as long
You seem to miss the definition of lastRow, which could be something like
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
then look carefully at .Range("A1:A10" & LastRow). Assume lastRow were 100 then this would set a range from A1 to A10100: is that what you want? Or may be you'd use
.Range("A1:A" & lastRow)
again .Range("A19" & aCell.Row) would lead to a single cell address such as "A1989" (were aCell.Row = 89): is that what you want?
other than what above I can't grasp the actual scenario of what you're searching where. You may want to provide more info about that

How to clear duplicate-named columns?

Actually i have to find a column named "account" and i have to delete the data entered in that column.
Lets say Column name "Account" is in the cell "B9" and values have been entered till "B30"(it is variable), then i have to delete the data from "B10"to "B30". And also if i have one more column in the name of "account", then i have to do the same for that column also.
I have coded for one column. I want to write it for multiple columns.
Here is my coding,
Private Sub CommandButton1_Click()
Dim xlapp As Excel.Application
Dim wb As Workbook
Dim FindRow As Range
Dim ad As String
Dim AcCell As String
Dim de As String
Dim lad As String
Dim col As Integer
Dim rw As Integer
Dim r As Integer
Dim rw2 As Integer
Dim myrange As Range
On Error GoTo ErrHandler:
MsgBox "Please browse for the document"
Set xlapp = CreateObject("Excel.Application")
filestr1 = Application.GetOpenFilename()
Workbooks.Open Filename:=filestr1 , Notify:=False
With xlapp
Set rng1 = ActiveSheet.UsedRange.Find("Account", , xlValues, xlWhole)
col = rng1.Column
'MsgBox col'
rw = rng1.Row
'MsgBox rw'
r = rw + 1
'MsgBox r'
ad = rng1.Address
'MsgBox ad'
ActiveSheet.Range(ad).Activate
ActiveCell.Offset(1, 0).Activate
rw2 = ActiveCell.Row
de = ActiveCell.Address
'MsgBox de'
ActiveSheet.Cells(Rows.Count, col).End(xlUp).Activate
lad = ActiveCell.Address
'MsgBox lad'
Set myrange = ActiveSheet.Range(de & ":" & lad)
myrange.Select
Selection.ClearContents
On Error GoTo ErrHandler:
filestr4 = Application.GetSaveAsFilename("RemovedAccNo")
ActiveWorkbook.SaveAs (filestr4)
On Error GoTo ErrHandler:
End With
Exit Sub
ErrHandler:
MsgBox ("User Cancelled.")
End Sub
You can do this with the FindNext Method
This method "continues a search that was begun with the Find method"
Also, try to not use Select and Activate. With lot of datas, it's very bad for the performance.
Finally, you may check the rng1 content after your Find to avoid Range Error with this line :
If Not rng1 Is Nothing Then

Non intersect address in Range

I have two ranges A2:E2 and B1:B5. Now if I perform intersect operation it will return me B2. I want some way through which I can get my output as B2 to be consider in any one range either A2:E2 and B1:B5. i.e if there is a repeated cell then it should be avoided.
Expected output :
A2,C2:E2,B1:B5
OR
A2:E2,B1,B3:B5
Can anyone help me.
Like this?
Sub Sample()
Dim Rng1 As Range, Rng2 As Range
Dim aCell As Range, FinalRange As Range
Set Rng1 = Range("A2:E2")
Set Rng2 = Range("B1:B5")
Set FinalRange = Rng1
For Each aCell In Rng2
If Intersect(aCell, Rng1) Is Nothing Then
Set FinalRange = Union(FinalRange, aCell)
End If
Next
If Not FinalRange Is Nothing Then Debug.Print FinalRange.Address
End Sub
OUTPUT:
$A$2:$E$2,$B$1,$B$3:$B$5
EXPLANATION: What I am doing here is declaring a temp range as FinalRange and setting it to Range 1. After that I am checking for each cell in Range 2 if it is present in Range 1. If it is then I am ignoring it else adding it using Union to the Range 1
EDIT Question was also cross posted here
From my article Adding a "Subtract Range" method alongside Union & Intersect
This code can be used to
Subtract the intersect of one range from a second range
Return the anti-union of two separate ranges (ie exclude only cells that intersetc)
I use this code in Mappit! to indentify hidden cells (ie Hidden Cells = UsedRange - SpecialCells(xlVisible)).
While this code is relatively lengthy it was written to be very quick on larger ranges, avoiding cell loops
Sub TestMe()
Dim rng1 As Range
Dim rng2 As Range
Set rng1 = [a2:e2]
Set rng2 = [b1:b5]
MsgBox RemoveIntersect(rng1, rng2) & " " & rng2.Address(0, 0)
End Sub
Function RemoveIntersect(ByRef rng1 As Range, ByRef rng2 As Range, Optional bBothRanges As Boolean) As String
Dim wb As Workbook
Dim ws1 As Worksheet
Dim rng3 As Range
Dim lCalc As Long
'disable screenupdating, event code and warning messages.
'set calculation to Manual
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
lCalc = .Calculation
.Calculation = xlCalculationManual
End With
'add a working WorkBook
Set wb = Workbooks.Add(1)
Set ws1 = wb.Sheets(1)
On Error Resume Next
ws1.Range(rng1.Address).Formula = "=NA()"
ws1.Range(rng2.Address).Formula = vbNullString
Set rng3 = ws1.Cells.SpecialCells(xlCellTypeFormulas, 16)
If bBothRanges Then
ws1.UsedRange.Cells.ClearContents
ws1.Range(rng2.Address).Formula = "=NA()"
ws1.Range(rng1.Address).Formula = vbNullString
Set rng3 = Union(rng3, ws1.Cells.SpecialCells(xlCellTypeFormulas, 16))
End If
On Error GoTo 0
If Not rng3 Is Nothing Then RemoveIntersect = rng3.Address(0, 0)
'Close the working file
wb.Close False
'cleanup user interface and settings
'reset calculation
With Application
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
lCalc = .Calculation
End With
End Function