Creating a dynamic loop for cells.find function - vba

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.

Related

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.

find cells that contain keywords in excel 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".

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.

How to delete rows that had formulas before value paste?

I got an spread sheet that include formulas and I wrote a vb code to value paste.
Depending on the input file number of rows that filled is varied and I need to delete the rows those had formulas and now empty. (This is using as connector and otherwise it some how pick these extra rows which is unnecessary)
Sheet2.Range("G2:G298").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Above code not doing anything...
If the blanks are results of a formula like:
=""
Entered into a cell and then copied and paste as values, those are not really blank cells.
Instead, those are cells that looks blank but contains zero length strings.
SpecialCells(xlCellTypeBlanks) and even Excel formula ISBLANK won't work on it.
One way is to loop through the range and check all that contains "" and delete it.
Dim c As Range, rngtodelete As Range
For Each c In Sheet2.Range("G2:G298")
If Len(c.Value) = 0 Then
If rngtodelete Is Nothing Then Set rngtodelete = c _
Else Set rngtodelete = Union(rngtodelete, c)
End If
Next
If Not rngtodelete Is Nothing Then rngtodelete.EntireRow.Delete xlUp
Another way is using AutoFilter like this:
Sheet2.Range("G2:G298").AutoFilter 1, "="
Sheet2.Range("G2:G298").SpecialCells(xlCellTypeVisible).EntireRow.Delete xlUp
I'm assuming that G2 does not contain your header but the start of your data.
If it happens to be your header, you'll need to use offset when deleting.
Sheet2.Range("G2:G298").Offset(1, 0) _
.SpecialCells(xlCellTypeVisible).EntireRow.Delete xlUp
Sheet2.AutoFilterMode = False
I'm not completely sure what you mean by "This is using as connector", but I believe it has to do with an export/import process to another application.
As mentioned, a zero length string is not the same as a truly blank cell. However, you can rid your worksheet of them easily. The fastest method I am aware of is a quick cyclic run through all of the columns, applying Text-to-Columns ► Fixed width ► Finish to each.
When that is done, the zero length strings will be reverted to truly blank cells but the worksheet's used range will still overlap those empty cells found at the bottom of the dataset. This means that any export to an external program will try to export those cells. Just run .UsedRange to get Excel to reevaluate the actual used range.
First, tap Ctrl+End to see what Excel thinks is the last used cell on the worksheet. Next, run the following macro.
Sub prep_for_export()
Dim c As Long
Debug.Print Sheets("Sheet1").UsedRange.Address(0, 0)
With Sheets("Sheet1")
For c = 1 To .Cells(1, Columns.Count).End(xlToLeft).Column
.Columns(c).TextToColumns Destination:=.Cells(1, c), _
DataType:=xlFixedWidth, FieldInfo:=Array(0, 1)
Next c
End With
Sheets("Sheet1").UsedRange
Debug.Print Sheets("Sheet1").UsedRange.Address(0, 0)
End Sub
Edit Sheet1 in all four places if you have to before running it.
That is a little homogeneous but I think it should work for your purposes. After running the macro, tap Ctrl+End back at your worksheet again to see what Excel thinks is the last used cell on your worksheet. The before and after range addresses were recorded to the VBE's Immediate window as well.