Find multiple strings, copy entire row and paste into another sheet - excel

I need to find certain names on a worksheet, copy the entire row once it finds said name and paste it on another worksheet.
I wrote code that finds one of the names, then copies the row and pastes it to another sheet.
Sub Macro2()
Dim StatusCol As Range
Dim Status As Range
Dim PasteCell As Range
Set StatusCol = Sheet10.Range("A1:AV1569")
For Each Status In StatusCol
If Sheet11.Range("A2") = "" Then
Set PasteCell = Sheet11.Range("A2")
Else
Set PasteCell = Sheet11.Range("A1").End(xlDown).Offset(1, 0)
End If
If Status = "Jane Thompson" Then Status.Offset(0, -4).Resize(1, 5).Copy PasteCell
Next Status
End Sub
Instead of finding only one string, the "Jane Thompson" name, I want to loop through a list of names, find each, copy the entire row where they are located and paste the row into another sheet. I have all the names on another worksheet (about 80 different names)
I managed to find code that gives me the desired output:
Sub FruitBasket()
Dim rngCell As Range
Dim lngLstRow As Long
Dim strFruit() As String
Dim intFruitMax As Integer
intFruitMax = 3
ReDim strFruit(1 To intFruitMax)
strFruit(1) = "Fruit 2"
strFruit(2) = "Fruit 5"
strFruit(3) = "Fruit 18"
lngLstRow = ActiveSheet.UsedRange.Rows.Count
For Each rngCell In Range("A2:A" & lngLstRow)
For i = 1 To intFruitMax
If strFruit(i) = rngCell.Value Then
rngCell.EntireRow.Copy
Sheets("Inventory").Select
Range("A65536").End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial xlPasteValues
Sheets("Fruit").Select
End If
Next i
Next
End Sub
But instead of 3 items in the array, I had to hard code 81 names. Is there any way to pull the items of an array from another sheet?

With the names in an array you can use Match rather than looping through them.
Option Explicit
Sub FruitBasket()
Dim ws As Worksheet, wsInv As Worksheet
Dim rngCell As Range, v As Variant, arNames
Dim lngLastRow As Long, lngInvRow As Long
With Sheets("Names")
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
arNames = .Range("A2:A" & lngLastRow)
End With
Set wsInv = Sheets("Inventory")
With wsInv
lngInvRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Application.ScreenUpdating = False
Set ws = ActiveSheet
With ws
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Each rngCell In .Range("A2:A" & lngLastRow)
' check if value is in array
v = Application.Match(rngCell, arNames, 0)
If IsError(v) Then
' no match
Else
' match
rngCell.EntireRow.Copy
lngInvRow = lngInvRow + 1
wsInv.Cells(lngInvRow, "A").PasteSpecial xlPasteValues
End If
Next
End With
Application.CutCopyMode = False
Application.ScreenUpdating = True
MsgBox "Done"
End Sub

Related

Copy 3rd Cell from under Same Row Where Col B is not empty

I have been trying to create a function which checks that if Col"B" <> Empty then copy the third cell which is under the same row.
I have this Data:
Where from i want to copy the Col"D" highlighted cells and paste them into same row where Col"B" <> empty.
Here is the final result. Your help will be appreciated in this regards.
Option Explicit
Sub CopyPasting()
Dim ws As Worksheet
Dim r As Long
Dim LastRow As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
LastRow = .Range("D" & .Rows.Count).End(xlUp).Row
For r = LastRow To 2 Step -2
If .Cells(r, "B") <> "" Then
.Rows(r + "D").Copy
.Rows(r + "D").PasteSpecial
n = n + 1
End If
Next
End With
End Sub
Please, try the next code:
Sub testRetOffset3()
Dim sh As Worksheet, lastR As Long, rngV As Range, rngFin As Range, c As Range
Set sh = ActiveSheet 'use here the sheet you need
lastR = sh.Range("B" & sh.rows.count).End(xlUp).row 'last sheet row
On Error Resume Next 'if not empty cells in column, it will not return the range and raise an error
Set rngV = sh.Range("B2:B" & lastR).SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If rngV Is Nothing Then Exit Sub 'stop the code if run on a wrong sheet, without empty cells in column B:B
For Each c In rngV.cells 'iterate between the discontinuous range cells
If rngFin Is Nothing Then 'if the final range is not set (first time)
Set rngFin = c.Offset(3, 2) 'set the range = the Offset necessary cell
Else
Set rngFin = Union(rngFin, c.Offset(3, 2)) 'make a Union between existing range and the Offset necessary cell
End If
Next
If Not rngFin Is Nothing Then 'copy both ranges in consecutive columns
rngV.Copy sh.Range("F2")
rngFin.Copy sh.Range("G2")
End If
End Sub
It will return in columns F:G, starting from the second row. It is easy to modify the range where to return...
You can even clear the existing processed columns and return in B:C, or in another sheet.
Edited:
In order to solve the last request, please use the next code:
Sub testRetOffsetMoreRows()
Dim sh As Worksheet, lastR As Long, rngV As Range, rngFin As Range, A As Range
Set sh = ActiveSheet
lastR = sh.Range("B" & sh.rows.count).End(xlUp).row
On Error Resume Next
Set rngV = sh.Range("A2:D" & lastR).SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If rngV Is Nothing Then Exit Sub
For Each A In rngV.Areas 'iterate between the range areas
If rngFin Is Nothing Then
Set rngFin = A.cells(1,2).Offset(3, 3) 'use the second cell of the area
Else
Set rngFin = Union(rngFin, A.cells(1,2).Offset(3, 3))
End If
Next
If Not rngFin Is Nothing Then
rngV.Copy sh.Range("H2")
rngFin.Copy sh.Range("L2")
End If
End Sub
But take care to have continuous ranges when have a value in column B:B. Otherwise, the code may fail... The areas property will return differently.
I wasn't sure where you wanted the output, this will put it into a sheet called "Sheet2". (You'll have to make that before running the code it won't create it for you.)
Dim i As Long
Dim j As Long
Dim lr As Long
Dim srcWS As Worksheet
Dim destWS As Worksheet
Set srcWS = ThisWorkbook.Sheets("Sheet1")
Set destWS = ThisWorkbook.Sheets("Sheet2")
With srcWS
lr = .Cells(.Rows.Count, 4).End(xlUp).Row
j = 2
For i = 2 To lr
If .Cells(i, 2).Value <> "" Then
destWS.Cells(j, 1).Value = .Cells(i, 2).Value
destWS.Cells(j, 2).Value = .Cells(i, 4).Offset(2, 0).Value
j = j + 1
End If
Next i
End With
If you need the colors copied over as well then use this:
.Cells(i, 4).Offset(2, 0).Copy
destWS.Cells(j, 2).PasteSpecial xlPasteAll
instead of:
destWS.Cells(j, 2).Value = .Cells(i, 4).Offset(2, 0).Value

How to make VBA code faster/more efficient

So I have designed this code to insert new entries into my master Database Log but when I run the code it is much too slow.
Private Sub CommandButton2_Click()
Dim ws As Worksheet
Dim LR As Long, i As Long, iRow As Long
Set ws = ThisWorkbook.Worksheets("Data Entry")
With ws
LR = .Cells(Rows.Count, 1).End(xlUp).Row
If 2 > LR Then Exit Sub
iRow = 3
For i = 1 To LR
If .Cells(i, 1).DisplayFormat.Interior.Color = RGB(217, 230, 251) Then
Worksheets("Call Log").Rows("3:3").Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
.Cells(i, 1).Resize(1, 7).Copy ThisWorkbook.Worksheets("Call Log").Cells(iRow, "A")
End If
Next i
End With
Set ws = Nothing
End Sub
As you can see, my code goes through the range, determines if it matches my criteria (in this case the color of the cell) and then Inserts a row in the destination Worksheet and copies the data into that newly created row over and over until it finishes. I've thought of maybe having it select all of the necessary cells, copy and then insert them all at once into the destination worksheet, but I'm not sure how to go about that.
Any help is greatly appreciated!
One of the things you are doing obsoletely, is copying something to the clipboard, while this is not necessary: instead of
Range("<somewhere>").Copy
Range("<elsewhere>").Paste
You might simply do:
Range("<elsewhere>".Value = Range("<somewhere>").Value
It's always a good idea to turn off screen updating and set calculations to manual (unless you need it)
Application.SceenUpdating = false
Application.calculations = xlmanual
Then set them back to true and xlautomatic at the end of the code.
Not sure if the syntaxes is correct, I'm typing from my phone
If you absolutely need to copy the source formatting of the cells also, then you could use a filter and then copy only the visible cells, all in one go. Something like this:
Private Sub CommandButton2_Click()
Const shtDataName As String = "Data Entry"
Const shtLogName As String = "Call Log"
Dim shtData As Worksheet
Dim shtLog As Worksheet
'
'Make sure required resources are available
Set shtData = GetWorksheet(shtDataName, ThisWorkbook)
If shtData Is Nothing Then
MsgBox "Missing sheet <" & shtDataName & ">!", vbInformation, "Cancelled"
Exit Sub
End If
Set shtLog = GetWorksheet(shtLogName, ThisWorkbook)
If shtLog Is Nothing Then
MsgBox "Missing sheet <" & shtLogName & ">!", vbInformation, "Cancelled"
Exit Sub
End If
'
'Check last row
Dim lastRow As Long
'
lastRow = shtData.Cells(Rows.Count, 1).End(xlUp).Row
If lastRow = 1 Then Exit Sub
'
Dim filterColor As Long
'
'Filter Range
filterColor = RGB(217, 230, 251)
With Range(shtData.Cells(1, 1), shtData.Cells(lastRow, 1))
.AutoFilter Field:=1, Criteria1:=filterColor, Operator:=xlFilterCellColor
End With
'
Dim rng As Range
Const lastCol As Long = 7
Dim firstRow As Long
'
'Get filtered range
'First row remains visible regardless of filter. Check it
If shtData.Cells(1, 1).Cells(1, 1).DisplayFormat.Interior.Color <> filterColor Then
firstRow = 2
Else
firstRow = 1
End If
On Error Resume Next
Set rng = Range(shtData.Cells(firstRow, 1), shtData.Cells(lastRow, lastCol)).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rng Is Nothing Then Exit Sub 'Nothing meets criteria
'
Dim tempArea As Range
Dim rCount As Long
'
'Get required rows count
For Each tempArea In rng.Areas
rCount = rCount + tempArea.Rows.Count
Next tempArea
'
'Insert rows
Const iRow As Long = 3
'
shtLog.Rows(iRow & ":" & iRow + rCount - 1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
rng.Copy shtLog.Cells(iRow, 1)
'
'Remove filter
rng.AutoFilter
End Sub
But, if you don't care about source formatting then you could use something like this:
Private Sub CommandButton2_Click()
Const shtDataName As String = "Data Entry"
Const shtLogName As String = "Call Log"
Dim shtData As Worksheet
Dim shtLog As Worksheet
'
'Make sure required resources are available
Set shtData = GetWorksheet(shtDataName, ThisWorkbook)
If shtData Is Nothing Then
MsgBox "Missing sheet <" & shtDataName & ">!", vbInformation, "Cancelled"
Exit Sub
End If
Set shtLog = GetWorksheet(shtLogName, ThisWorkbook)
If shtLog Is Nothing Then
MsgBox "Missing sheet <" & shtLogName & ">!", vbInformation, "Cancelled"
Exit Sub
End If
'
'Check last row
Dim lastRow As Long
'
lastRow = shtData.Cells(Rows.Count, 1).End(xlUp).Row
If lastRow = 1 Then Exit Sub
'
'Read data in array (super fast)
Dim rng As Range
Dim arrData() As Variant
Const lastCol As Long = 7
'
Set rng = Range(shtData.Cells(1, 1), shtData.Cells(lastRow, lastCol))
arrData = rng.Value2
'
'Store relevant row numbers
Dim collRows As New Collection
Dim i As Long
Dim filterColor As Long: filterColor = RGB(217, 230, 251)
'
For i = LBound(arrData) To UBound(arrData)
If rng.Cells(i, 1).DisplayFormat.Interior.Color = filterColor Then
collRows.Add i
End If
'
'I am not a fan of using colors for filtering. It's much faster to have a separate
' column (indicator column) that can be used for that. This way we could do
' something like: If arrData(i, indCol) = expectedValue Then ...
' which is much faster than accesing cells
Next i
'
'Prepare data for writing
Dim arrFiltered() As Variant
ReDim arrFiltered(1 To collRows.Count, 1 To lastCol)
Dim r As Variant
Dim c As Long
'
i = 0
For Each r In collRows
i = i + 1
For c = 1 To lastCol
arrFiltered(i, c) = arrData(r, c)
Next c
Next r
'
'Insert rows
Const iRow As Long = 3
'
shtLog.Rows(iRow & ":" & iRow + collRows.Count - 1).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
'
'Write
With Range(shtLog.Cells(iRow, 1), shtLog.Cells(iRow + collRows.Count - 1, lastCol))
.Value2 = arrFiltered
End With
End Sub
Private Function GetWorksheet(ByVal sheetName As String, ByVal book As Workbook) As Worksheet
On Error Resume Next
Set GetWorksheet = book.Worksheets(sheetName)
On Error GoTo 0
End Function
The above is rushed code but proves some ways of doing the task. Other things that need to be considered are:
Are the worksheets protected? if yes, filtering and inserting rows can be an issue
Inserting rows will fail if the rows are intersecting multiple dynamic tables (listobjects)
Code needs to be changed if data doesn't start on row 1 in the source
and probably others that don't come to mind right now

Looping in text filter

I have this code which cuts and pastes an entire row to another sheet. When i set values as = it works, but when i set to like or contains, the loop doesnt happen. The value of the filter i'm looking for would keep changing including with a unique phrase. Eg: 1. Overlap error: 1234, 1. Overlap error:1235 etc.
Sub loopMe()
Dim sh As Worksheet, ws As Worksheet
Dim LstR As Long, rng As Range, c As Range
Set sh = Sheets("Sheet1") 'set the sheet to loop
Set ws = Sheets("Sheet2") 'set the sheet to paste
With sh 'do something with the sheet
LstR = .Cells(.Rows.Count, "BE").End(xlUp).Row 'find last row
Set rng = .Range("BE5:BE" & LstR) 'set range to loop
End With
'start the loop
For Each c In rng.Cells
'If c = "1. Overlap error:" Then
If c.Value Like "*1. Overlap error:*" Then
'If Left(c.Value, 17) = "1. Overlap error:" Then
'If InStr(1, c, "1. Overlap error:") > 0 Then
c.EntireRow.Copy ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(1) 'copy row to first empty row in sheet2
c.EntireRow.Delete Shift:=xlUp
End If
Next c
End Sub
You can use a filter to find the data, move it and delete the rows.
Sub ed()
Dim sh As Worksheet, ws As Worksheet
Dim rng As Range
Set sh = Sheets("Sheet1")
Set ws = Sheets("Sheet2")
With sh
.Range("BE4").AutoFilter Field:=1, Criteria1:= _
"=*1. Overlap error:*", Operator:=xlAnd
Set rng = .Range("BE5:BE" & .Cells(.Rows.Count, "BE").End(xlUp).Row)
With ws
rng.SpecialCells(xlCellTypeVisible).EntireRow.Copy ws.Cells(ws.Rows.Count, "A").End(xlUp).Offset(1)
End With
rng.EntireRow.Delete
.AutoFilterMode = False
End With
End Sub
So if you prefer your original approach,
Sub loopMe()
Dim sh As Worksheet, ws As Worksheet
Dim LstR As Long, c As Range
Set sh = Sheets("Sheet1")
Set ws = Sheets("Sheet2")
'find last row
LstR = sh.Range("BE65000").End(xlUp).Row
Dim irow
For irow = LstR To 5 Step -1
Set c = sh.Range("BE" & irow)
If c.Value Like "*1. Overlap error:*" Then
'copy row to first empty row in sheet2
c.EntireRow.Copy ws.Cells(65000, 1).End(xlUp).Offset(1, 0)
c.EntireRow.Delete Shift:=xlUp
End If
Next irow
End Sub

Extract text from string based on value of a cell in another worksheet

I have a workbook with a series of sheets that I need to run a code to resolve the data.
I have one worksheet with a list of "codes" and another sheet that has cells that will include a string of codes.
I am trying to create a macro that allows me to reference a code in sheet1 A1, and then look through B:B in sheet2 and copy the row if the code appears in the string
I am a novice VBA user and have tried googling a few things and I'm not having any luck.
Edit:
I have managed to get something that does copy the data through, but there seems to be an issue in the For loop as all lines are copied in, not just the lines that match. Code below.
Private Sub CommandButton1_Click()
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
I = Worksheets("MASTER LIST").UsedRange.Rows.Count
J = Worksheets("VALIDATED LIST").UsedRange.Rows.Count
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("VALIDATED LIST").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("MASTER LIST").Range("E1:E" & I)
On Error Resume Next
Application.ScreenUpdating = True
For K = 1 To xRg.Count
If CStr(xRg(K).Value) = InStr(Worksheets("MASTER LIST").Range("E1:E" & I).Value, Worksheets("TRANSPOSED DATA NO SPACES").Range("B1:B" & J)) > 1 Then
xRg(K).EntireRow.Copy Destination:=Worksheets("VALIDATED LIST").Range("A" & J + 1)
J = J + 1
End If
Next
Application.ScreenUpdating = True
End Sub
Further Edit:
I want to be able to use the list of feature codes and look them up in the master list.
If the VBA code finds the feature code in the strings in the master list, then I need to copy the row and paste it into a blank sheet that will be called validated list.
Sub look_up_copy()
Dim last_row As Integer
Dim cell As Range
Dim Cells As Range
last_row = ThisWorkbook.Worksheets(2).Cells(ThisWorkbook.Worksheets(2).Rows.Count, "B").End(xlUp).Row
Set Cells = ThisWorkbook.Worksheets(2).Range("B1:B" & last_row)
For Each cell In Cells:
If cell.Value = ThisWorkbook.Worksheets(1).Range("A1").Value Then
cell.EntireRow.Copy
End If
Next cell
End Sub
You didn't say anything about wanting to paste, but if you do then just insert it after the copy line.
this should work, just remove duplicates on sheet3 after running. This is a double loop in which, for each cell in column B of sheet 2, the macro will check all values from sheet1 Column A. You will see duplicate lines in the end, but it doesn't matter right? all you need is remove dupes
Sub IvanAceRows()
Dim cell2 As Range, cells2 As Range, cell1 As Range, cells1 As Range
Dim lastrow2 As Long, lastrow1 As Long
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Dim i As Long, ii As Long, iii As Long
Set ws1 = Worksheets("USAGE CODES")
Set ws2 = Worksheets("MASTER LIST")
Set ws3 = Worksheets("VALIDATED LIST")
lastrow1 = ws1.cells(Rows.Count, 1).End(xlUp).Row
lastrow2 = ws2.cells(Rows.Count, 2).End(xlUp).Row
Set cells1 = ws1.Range("A1:A" & lastrow1)
Set cells2 = ws2.Range("B1:B" & lastrow2)
iii = 1
For ii = 1 To lastrow2
For i = 1 To lastrow1
If InStr(1, ws2.cells(ii, 2), ws1.cells(i, 1)) <> 0 Then
ws2.cells(ii, 2).EntireRow.Copy
ws3.Activate
ws3.cells(iii, 1).Select
Selection.PasteSpecial
iii = iii + 1
End If
Next i
Next ii
End Sub
Without seeing your spreadsheet, I assumed all of your 'codes' are listed in Column A in sheet1, and all of those code strings are also in sheet2 in column B. my code allows u to find each string from sheet1 in Column B of sheet2. Once found, it will be pasted into Sheet3 starting from the 2nd row.
Sub IvanfindsRow()
Dim i As Long
Dim lastrow1 As Long
Dim lastrow2 As Long
Dim Code As String
Dim search As Range
lastrow1 = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
lastrow2 = Worksheets("Sheet2").Cells(Rows.Count, 2).End(xlUp).Row
Worksheets("Sheet3").Range("A1").Select
For i = 1 To lastrow1
Code = Worksheets("Sheet1").Cells(i, 1).Value
Set search = Worksheets("Sheet2").Range("B1:B22").Find(what:=Code, lookat:=xlWhole)
If Not search Is Nothing Then
search.EntireRow.Copy
ActiveCell.Offset(1, 0).Select
Selection.PasteSpecial
Else 'do nothing
End If
Next i
Application.CutCopyMode = False
End Sub

Excel VBA to dynamically filter data

Screenshot of SourceReport Excel that need to be filtered.I need to develop a Excel VBA code to filter data on a worksheet, based on the filter conditions provided on the same worksheet.
Below is the code written for the same .. But this code filter the data from Row 1 instead of Row 4. Can you suggest an improvement?
Sub colFilter()
Dim ShtSource As Worksheet
Dim shtSrcHead As Range
Dim shtFilterData As Range
Dim filterStr As String
Set ShtSource = Sheets("SourceReport")
Dim lastCol As Long
Dim j As Long
Dim iCntr As Long
'get all of the filters of sheet , assuming in row 2
lastCol = ShtSource.Cells(1, Columns.Count).End(xlToLeft).Column
Set shtSrcHead = ShtSource.Range("A2", ShtSource.Cells(1, lastCol))
Set shtFilterData = ShtSource.Range("A4", ShtSource.Cells(1, lastCol))
j = 0
'actually loop through and find values
For Each srcHead In shtSrcHead
j = j + 1
If j = lastCol Then
j = 0
End If
If srcHead.Value = "INCLUDE" Or srcHead.Value = "EXCLUDE" Then
filterStr = srcHead.Offset(1, 0).Value
If srcHead.Value = "INCLUDE" Then
Debug.Print filterStr
Debug.Print j
shtFilterData.AutoFilter Field:=j, Criteria1:=filterStr
End If
If srcHead.Value = "EXCLUDE" Then
Debug.Print filterStr
Debug.Print j
shtFilterData.AutoFilter Field:=j, Criteria1:="<>" & filterStr
End If
End If
Next srcHead
MsgBox "Done!"
End Sub
As per below screenshot use the following sub to filter for multiple condition.
Sub MyFilter()
Dim include() As String
Dim exclude As String
Dim FiltRng As Range
Dim RngArea, RngArea2 As Range
'Set RngArea = Application.InputBox(prompt:="Select range include criteria.", Type:=8)
'Set RngArea2 = Application.InputBox(prompt:="Select range exclude criteria.", Type:=8)
'include = Split(RngArea, ",")
include = Split(Range("C2"), ",")
exclude = Range("B2")
Set FiltRng = Sheet1.Range("B4:C11")
FiltRng.AutoFilter Field:=2, Criteria1:=include, Operator:=xlFilterValues
FiltRng.AutoFilter Field:=1, Criteria1:="<>" & exclude
End Sub
Data position Screenshot
Adjust code for your data ranges.

Resources