find cells that contain keywords in excel VBA - vba

I would like to write a macro that searches through a column in a database and returns, in a different tab, all the cells that contain a certain given keyword. In other words, I want to type in "hammer" and get a list of every cell that contains the word hammer, even if the word is in the middle of the value (for example, "the builder bought a hammer yesterday").
I'm fairly new to VBA so I would like some help/input on what functions to use to do this. I've tried to use AdvancedFilter, however that only looks at the very beginning of each cell value. All feedback is welcome, thank you!

use Autofilter() method of Range object
Sub main()
With Worksheets("hammer") '<--| reference searched worksheet (change "hammer" to its actual name)
With .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)) '<--| reference its column "A" cells from row 1 down to last non empty one (change "A"s to your actual searched column index)
.AutoFilter Field:=1, Criteria1:="*hammer*" '<--| filter on referenced column to get cell containing "hammer"
If Application.WorksheetFunction.Subtotal(103, .Cells) > 1 Then .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy Destination:=Worksheets("different tab").Range("A1") '<--| copy any filtered cell into "different tab" worksheet
End With
.AutoFilterMode = False '<--| show all rows back
End With
End Sub
it assumes the first cell of searched range ("A1" in this example) is a header cell, so that it won't be searched for "*hammer".

Related

On the selection of a single cell

As in https://www.ozgrid.com/VBA/special-cells.htm the author says:
when/if one specifies only a single cell (via Selection or Range)
Excel will assume you wish to work with the entire Worksheet of cells.
My following code (See the result) does select a single cell and the .SpecialCells(xlConstants) method does operate on the entire sheet marking all the cells with a constant red. My question is, however, why selection.Value = 1000 only works only on the single selected cell ("A1"), instead of the whole worksheet (that is all the cells are filled with 1000), According to the logic applied to the .SpecialCells(xlConstants) method?
Sub stkOvflSep7()
' This sub marks red the cells with a constant
' The first cell is selected
' Some other cells are filled with constant
Dim constantCells As Range
Dim cell As Range
Worksheets("Sheet5").Cells.Clear
activesheet.Cells.Interior.Color = xlNone
Range("c1:d4").Value = 2
Range("a1").Select
ActiveCell.Select
selection.Value = 1000 ' The first cell is selected
' Set constantCells = Range("A1").SpecialCells(xlConstants)
Set constantCells = selection.SpecialCells(xlConstants)
For Each cell In constantCells
If cell.Value > 0 Then
cell.Interior.Color = vbRed ' marks red the cells with a constant
End If
Next cell
End Sub
A cell is a cell (and not the entire worksheet) for every property and method.
The speciality you quoted...
As in https://www.ozgrid.com/VBA/special-cells.htm the author says:
when/if one specifies only a single cell (via Selection or Range) Excel will assume you wish to work with the entire Worksheet of cells.
...is because in Excel you can either select a single cell or a range of cells, but you can't deselect everything. For that reason - and because searching and/or selecting specials-cells within a single cell isn't very useful - excel uses the complete sheet for these two functions (i'm not completely sure if there is another function) when only a single cell is selcted (or referenced as range). If more than one cell is selected/referenced excel uses these cells for searching. This is the same for running searches etc. manually on the sheet.
You're not really doing the same thing as the linked article, since you are assigning to a variable, rather than selecting Range("A1").SpecialCells(xlConstants).
I suspect the usedrange version would work though.

Lookup in all the sheets for specific text and if match then write value of same row but different column value to master sheet

check over all sheets
If specific text (e.g., yes) is found in the fifth row of a sheet, get data from that row (but different column) and write data to a master sheet
How can I do that?
I found below code relatively useful for me but, not 100% matching with my requirement. please help me on this.
Problem in this code is:- i have specific text(yes) in specific range(e6:e16).
What I want is to check for only yes word. If found then write value of column A & row, in which yes word found, into master sheet and check it till last sheet.
Sub SeachSheets()
Dim FirstAddress As String, WhatFor As String
Dim Cell As Range, Sheet As Worksheet
WhatFor = InputBox("What are you looking for?", "Search Criteria")
If WhatFor = Empty Then Exit Sub
For Each Sheet In Sheets
If Sheet.Name <> "SEARCH" Then
With Sheet.Columns(1)
Set Cell = .Find(WhatFor, LookIn:=xlValues, LookAt:=xlPart)
If Not Cell Is Nothing Then
FirstAddress = Cell.Address
Do
Cell.EntireRow.Copy _
Destination:=Sheets("SEARCH").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Set Cell = .FindNext(Cell)
Loop Until Cell Is Nothing Or Cell.Address = FirstAddress
End If
End With
End If
Next Sheet
Set Cell = Nothing
End Sub
Any help will be appreciated.
Thank you.
For one sheet, this is easy to accomplish with a formula alone, e.g.
= INDEX(1:1,MATCH("yes",5:5,0))
This finds the first instance of yes in the 5th row of the current sheet, and returns the value in 1st row and in the same column.
One option is to have this formula above somewhere on each sheet in your workbook as a "helper cell" (e.g. cell Z99) and then have a formula somewhere on your master sheet to check all of these helper cells, e.g.
= IFERROR(Sheet1!Z99,IFERROR(Sheet2!Z99,IFERROR(Sheet3!Z99,IFERROR(...,"no match"))))
Of course, also possible without helper cells at all, but the formula just gets messy:
= IFERROR(INDEX(Sheet1!1:1,MATCH("yes",Sheet1!5:5,0)),
IFERROR(INDEX(Sheet2!1:1,MATCH("yes",Sheet2!5:5,0)),
IFERROR(INDEX(Sheet3!1:1,MATCH("yes",Sheet3!5:5,0)),
IFERROR(...,"no match"))))
If you want a way without explicitly calling each sheet, then VBA is probably required. Just posting a solution without VBA to see if this will work for you.

Compare Cell Data and Copy

I found this great snip of code and I am trying to manipulate it to work for me, but I just can't seem to get it. Unfortunately I haven't been able to get my head around it to fully understand it, which doesn't help. So I turn to you. I need to evaluate a column of cells and look for either similarities or differences. If a cell in sheet 1 column 1 is not the same as any of the cells in sheet 2 column 1, I want to copy the entire row into sheet 1 at the bottom of the used area. I've gotten this to the point where what you see will copy the correct first cell, but I can't manipulate it to copy the entire row. I think because of how the 'With' is structured but I need to try to stay away from doing loops since there is over 30k cells to evaluate.
Going down the road I will also be wanting to look for duplicates using the same method above, and if there is a duplicate, compare the adjacent cells for differences and if there is a difference, move the existing data into a comment and move the new data into the existing cell.
Any and all advice is, as always, very appreciated.
Sub Compare_Function()
Call Get_Master_Cell_Info
Application.ScreenUpdating = False
With Sheets("Update").Range(Cells(4, 1), Cells(Rows.Count, 1).End(xlUp)).Offset(, 1)
.Formula = "=VLOOKUP(A4,'New Master Data 6.1'!A:A,1,FALSE)"
.Value = .Value
.SpecialCells(xlCellTypeConstants, 16).Offset(, -1).Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
.ClearContents
End With
Application.ScreenUpdating = True
End Sub
Quick line by line breakdown
This just takes the entire used range from cells A4 to the last used cell in columnA then offsets it by one column so B4:Bx (x is the last used row in column A)
With Sheets("Update").Range(Cells(4, 1), Cells(Rows.Count, 1).End(xlUp)).Offset(, 1)
This puts the formula in all cells so it looks up A4,A5,A6, etc in master sheet, returns the value in the master sheet or an error if its not found. It then copies the values over so they are hardcoded in
.Formula = "=VLOOKUP(A4,'New Master Data 6.1'!A:A,1,FALSE)"
.Value = .Value
Specialcells looks for constants (all cells) and value 16 which means error cells (ie cells don't exist) offsets by -1 (so column A) and copies to new sheet column A at rows.count+1
.SpecialCells(xlCellTypeConstants, 16).Offset(, -1).Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
You might also want to do this after you .clearcontents so you don't get all the error cells in column B
to fix it just change the copied range to .entirerow so
.SpecialCells(xlCellTypeConstants, 16).entirerow.Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
You will also copy the errors in column B but with this structure there is no getting around that. Can always erase them from the master sheet after.
Also note this code will overwrite any data you have stored in column B.
One more note this code depends on the sheet update being active, it won't run otherwise since your cells function inside your range needs the worksheet explicitly stated, as does your rows.count. You would be better wrapping the whole thing in 2 withs, one for the sheet and one with the range (using .cells and .rows.counmt)

How to move to next blank cell?

I have data on multiple sheets in a workbook that I want copied all to one sheet in that same workbook. When I run the macro, I would like it to start by deleting the current data in the "iPage Data Export" sheet and then replacing it with data from the other sheets.
I want the process to occur one column at a time since I may not bring over everything. Right now I am trying to learn how to do just one column.
I was able to get it to copy all of the contents of a column from one sheet, but when it moves to the next sheet, it overwrites the existing data. In the end, I only get one sheets worth of data copied.
Here are my 4 problems:
How do I make it clear the data on this sheet before running the routine?
How can I make it start each copy function at the bottom of that row (i.e. after the last cell with a value)? I have tried many of the suggestions on this and other boards without success. I will admit I am not very experienced in this.
How can I make it copy to a particular column (currently it just seems to default to A.
How can I concatenate multiple columns during the paste function? I.e. what if I want it to insert: A2&", "B2 instead of just A2
Sub CombineData()
Dim Sht As Worksheet
For Each Sht In ActiveWorkbook.Worksheets
If Sht.Name <> "iPage Data Export" Then
Sht.Select
Range("C:C").Copy
Sheets("iPage Data Export").Select
ActiveSheet.Paste
Else
End If
Next Sht
End Sub
How do I make it clear the data on this sheet before running the routine?
Sht.Cells.ClearContents
How can I make it start each copy function at the bottom of that row (i.e. after the last cell with a value)? I have tried many of the suggestions on this and other boards without success. I will admit I am not very experienced in this.
Range("C" & Rows.Count).End(xlUp).Offset(1, 0)
In detail:
Rows.Count will return the number of rows in the sheet, so in the legacy style *.xls workbooks this would return the number 65,536. Therefore "C" & Rows.Count is the same as C65536
Range("C" & Rows.Count).End(xlUp) is the same as going to C65536 and pressing Ctrl + ↑ - The command End(xlDirection) tells the program to go the last cell in that range. In this case, we would end up at the last cell containing data in column C.
.Offset(1, 0) means that we want to return the range offset by an amount of rows and/or columns. VBA uses RC (Rows Columns) references, so whenever you see something like the Offset() function with two numbers being passed as the arguments, it usually relates to the row, and the column, in that order. In this case, we want the cell that is one row below the last cell we referenced.
All-in-all the phrase Range("C" & Rows.Count).End(xlUp).Offset(1, 0) means go to the last cell in column C, go up until we hit the last cell with data, and then return the cell below that - which will be the next empty cell.
How can I make it copy to a particular column (currently it just seems to default to A.
Range("C:C").Copy Destination:=Sheets("iPage Data Export").Range("A:A")
You can pass the Destination argument in the same line and actually bypass the clipboard (faster and cleaner)
How can I concatenate multiple columns during the paste function? I.e. what if I want it to insert: A2&", "B2 instead of just A2
Lets say you wanted to reference column A, B, and F - just use:
Range("A1, B1, F1").EntireColumn
To summarise, you could streamline your existing code to something like (untested):
Sub CombineData()
Dim Sht As Worksheet
For Each Sht In ActiveWorkbook.Worksheets
If Sht.Name <> "iPage Data Export" Then
Sht.Range("C1:C" & Cells(Sht.Rows.Count, 3).End(xlUp).Row).Copy Destination:=Sheets("iPage Data Export").Range("A:A")
End If
Next
End Sub
This should do for the copying:
Sub CombineData()
Dim sheet As Worksheet
For Each sheet In Worksheets
If (sheet.Name <> "iPage Data Export") Then
sheet.Select
Range("A1", ActiveCell.SpecialCells(xlLastCell)).Select
Selection.Copy
Worksheets("iPage Data Export").Activate
Cells(1, ActiveCell.SpecialCells(xlCellTypeLastCell).Column + 1).Select
ActiveSheet.Paste
End If
Next
End Sub
For the concatenation you need to be more specific - but I guess you should open a new question with a clearer focus if you need specific help on that.

Creating a dynamic loop for cells.find function

Creating a macro that will take the cell.value (string) in worksheet A then go to Worksheet B, using the cells.find method locate the cell which match the string.
Example
SheetA.activecell.value = "Harry Potter"
set myvar = SheetA.activecell.value
sheetB.select
Cells.Find(What:=myvar, After:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False).Select
Assuming the above syntax is correct, the cell in worksheet A which contains the string "Harry Potter" will be selected automatically.
This is where my problems come in. I want to do a loop through an entire column, executing the Cells.Find function for each cell in the column.
For example, SheetA.cells(3 ,1) contains "Harry Potter". Using the offset function on every completion of the loop, the cell containing the value to be found will be offset by 1 row.
So, in the next iteration of the loop, Cells(4, 1) in SheetA will contain the value to be used in the cells.find function.
Say, that value is the string "Iphone Charger". Then, cells.find(what:=myvar (Basically myvar = "Iphone Charger") would be executed in worksheet B.
And so on down the column in worksheet A.
Secondly, I want to copy certain values in worksheets A.
Scenario:
If "Harry Potter" is found in sheetA then
Do an `activecell.offset` function to copy some values in the same row as the cell in sheet A and
Copy those values to worksheet B using Copy destination
Else if "Harry Potter" can be found then
Jump to the next cell value.
End if
Keep looping until worksheet B hits an empty cell, that is cells(X , 1).value = ""
Then the whole macro ends
Have been killing my brain cells to resolve this issue and would appreciate if any of you guys in this forum can help me.
I'd recommend using the For Each construct for your main loop on the cells with values to find in worksheet A. In pseudocode:
For each cell in column A of sheet A
With the sheet B range to look in
If cell value is ""
Exit the sub
Else
result = .find the cell value
If the find is successful ("Not result is nothing")
Copy sheetA.cells(cell.row, <column of interest>) to sheet B
Copy ... (cell.row,<another column of interest>) ...
End the If
End the if
End the with
Next cell
Note that this looks for only one instance of each value in column A of sheet A.
As Jaycal noted, you would need to use FindNext to find additional instances after the first one.
The basic idea is to find the first instance and save its address, then use a do loop with FindNext to look for more instances. The do loop keeps executing until FindNext finds a cell with the same address as the address you saved for the first instance that was found.
For a code example of this, see this explananation or this one, among many others that can be found on the web.