I have total email ids in COL A of Sheet 1 and bounced email ids in COL A of Sheet 2. I want to delete Sheet 1 values or entire rows based on values on Sheet 2.
I tried the following code but doesn't work.
Public Sub delete_selected_rows()
'look at sheet2, A1 through A3 for search values
For Each search_value In Worksheets("Sheet2").Range("A1:A3")
'as long as there is something to delete...
Do While Not Worksheets("Sheet1").Range("A1:A3"). _
Find(search_value.Value, lookat:=xlWhole) Is Nothing
'...delete that row
Worksheets("Sheet1").Range("A1:A3").Find(search_value.Value, _
lookat:=xlWhole).EntireRow.Delete
Loop
Next
End Sub
Any help ?
I would use this one:
Public Sub delete_selected_rows()
Dim rng1 As Range, rng2 As Range, rngToDel As Range, c As Range
Dim lastRow as Long
With Worksheets("Sheet1")
lastRow = .Cells(.Rows.Count,"A").End(xlUp).Row
Set rng1 = .Range("A1:A" & lastRow)
End With
Set rng2 = Worksheets("Sheet2").Range("A:A")
For Each c In rng1
If Not IsError(Application.Match(c.Value, rng2, 0)) Then
'if value from rng1 is found in rng2 then remember this cell for deleting
If rngToDel Is Nothing Then
Set rngToDel = c
Else
Set rngToDel = Union(rngToDel, c)
End If
End If
Next c
If Not rngToDel Is Nothing Then rngToDel.EntireRow.Delete
End Sub
Try this:
Sub Macro1()
Dim lrow As Long
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
With ws1
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("B1:B" & lrow)
.Formula = "=IFERROR(MATCH(A1," & ws2.Name & "!A:A,0),"""")"
.Value = .Value
.AutoFilter 1, "<>"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
End With
End Sub
Related
I am looking for some assistance... Below is a code and some images of what I am attempting to acheive. I have created a selector which when you enter a qty. I want it to take the line with the quantity included and take it to another sheet on the next available line. My code is not yielding an error but neither is it doing anything at all.
I wish to take range J:P of the line with a qty entered and then paste it into the other worksheet in the next blank row of column D as there will be entries already included in A-C. Can anyone here help?
Sub Add()
Dim searchRange As Range
Dim foundCell As Range
Dim mysearch As Integer
Dim iRow As Long
Dim ws1, ws2 As Worksheet
Set ws1 = Worksheets("Output")
Set ws2 = Worksheets("Selector")
iRow = Sheets("Output").Range("D2").End(xlUp) + 1
mysearch = Sheets("Selector").Range("N10").Value
With Sheets("Selector")
Set searchRange = Sheets("Selector").Range("N12:N35") ', .Range("A" & .Rows.Count).End(xlUp))
End With
Set foundCell = searchRange.Find(what:=mysearch, Lookat:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not foundCell Is Nothing Then
ws1.Cells(iRow, 4).Value = foundCell.Offset(0, -4).Value
'and so on
End If
End Sub
This is the selector
This is where I would like to paste the values (in a different order).
Try the following, I've simply amended your code slightly, and I believe it should work as expected:
Sub Add()
Dim foundCell As Range
Dim mysearch As Integer
Dim iRow As Long, Last As Long
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = Worksheets("Output")
Set ws2 = Worksheets("Selector")
iRow = ws1.Cells(ws1.Rows.Count, "D").End(xlUp).Row + 1
Last = ws2.Cells(ws2.Rows.Count, "N").End(xlUp).Row
mysearch = ws2.Range("N10").Value
Set foundCell = ws2.Range("N12:N" & Last).Find(what:=mysearch, Lookat:=xlWhole)
If Not foundCell Is Nothing Then
ws1.Cells(iRow, 4).Value = foundCell.Offset(0, -4).Value
End If
End Sub
Instead of hard coding the value to be looked up ("1234"), I would like to use a range of values, on a separate worksheet("Items") to use as the search criteria.
I would also like to substitute that same value for the destination sheet.
For example, the first value in the range could be "8754", I would like the code to look for this value then paste the columns, A,B,C,F and the cell containing the value onto the worksheet "8754". (I have all of the worksheets created already)
TIA
Sub Test()
Dim Cell As Range
With Sheets("Sheet1") 'Sheet with data to check for value
For Each Cell In .Range("H1:H" & .Cells(.Rows.Count, "H").End(xlUp).Row)
pos = InStr(Cell.Value, "1234")
If pos > 0 Then
NextFreeRow = Sheets("Sheet2").Cells(Sheets("Sheet2").Rows.Count,
"A").End(xlUp).Row + 1
'get the next empty row to paste data to
.Range("A" & Cell.Row & ",B" & Cell.Row & ",C" & Cell.Row & ",F" &
Cell.Row & "," & Cell.Address).Copy Destination:=Sheets("Sheet2").Range("A" & NextFreeRow)
End If
Next Cell
End With
End Sub
This uses FIND rather than FILTER to copy the correct rows.
The Main procedure defines the range you're searching and which values will be searched for. The FindValues procedure finds the value and copies it to the correct sheet.
This assumes that Sheet3!A1:A3 contains a unique list of values to be searched for and the these values can be found in Sheet1!H:H.
It also assumes that all sheets already exist.
Public Sub Main()
Dim rToFind As Range
Dim rValue As Range
Dim rSearchRange As Range
With ThisWorkbook
'Update to the range being searched.
With .Worksheets("Sheet1")
Set rSearchRange = .Range("H1", .Cells(.Rows.Count, 8).End(xlUp))
End With
'Update to the range containing the values to be searched for.
Set rToFind = .Worksheets("Sheet3").Range("A1:A3")
End With
'Passe each of the values to be searched to the FindValues procedure.
For Each rValue In rToFind
FindValues rValue, rSearchRange
Next rValue
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Alternative method to look for hard-coded values.
' `ValuesToFind` in FindValues procedure will needed changing to a Variant.
'
' Dim vAlternativeSearch As Variant
' Dim vAlternativeValue As Variant
' vAlternativeSearch = Array(1475, 1683, 219)
'
' For Each vAlternativeValue In vAlternativeSearch
' FindValues vAlternativeValue, rSearchRange
' Next vAlternativeValue
End Sub
Public Sub FindValues(ValueToFind As Range, RangeToSearch As Range)
Dim rFound As Range
Dim sFirstAddress
Dim rLastUsedCell As Range
'Find the next available row on the referenced sheet.
With ThisWorkbook.Worksheets(CStr(ValueToFind))
Set rLastUsedCell = .Range("A1", .Cells(.Rows.Count, 1).End(xlUp)).Offset(1)
End With
With RangeToSearch
'Find the first value.
Set rFound = .Find(What:=ValueToFind, _
After:=RangeToSearch.Cells(RangeToSearch.Cells.Count), _
LookAt:=xlPart, _
SearchDirection:=xlNext)
'If the first value exists then remember the address, copy the cells to the
'correct sheet and look for the next row with the same value. Stop when
'it reaches the first address again.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
'You may have to muck around with this to get the correct range to copy.
'If rFound is in column H this will copy columns B:D and F.
Union(rFound.Offset(, -6).Resize(, 3), rFound.Offset(, -2)).Copy Destination:=rLastUsedCell
Set rLastUsedCell = rLastUsedCell.Offset(1)
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
End If
End With
End Sub
Edit 1:
You say the worksheets already exists, but in your comment you say put it in a brand new sheet.
To add a new sheet add this function:
Public Function WorkSheetExists(SheetName As String, Optional WrkBk As Workbook) As Boolean
Dim wrkSht As Worksheet
If WrkBk Is Nothing Then
Set WrkBk = ThisWorkbook
End If
On Error Resume Next
Set wrkSht = WrkBk.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
and then add this code directly after the variable declaration in the FindValues procedure:
Dim wrkSht As Worksheet
If Not WorkSheetExists(CStr(ValueToFind)) Then
Set wrkSht = ThisWorkbook.Worksheets.Add
wrkSht.Name = CStr(ValueToFind)
End If
Edit 2:
This updated code searches columns Q:Z, returns the values from A:L as well as the found cell.
To update from the original code I had to change rSearchRange to look from Q1 to column 26, and update the Copy/Paste line to return the correct range.
Public Sub Main()
Dim rToFind As Range
Dim rValue As Range
Dim rSearchRange As Range
With ThisWorkbook
'Update to the range being searched.
With .Worksheets("Data")
Set rSearchRange = .Range("Q1", .Cells(.Rows.Count, 26).End(xlUp))
End With
'Update to the range containing the values to be searched for.
Set rToFind = .Worksheets("Items").Range("A1:A2")
End With
'Passe each of the values to be searched to the FindValues procedure.
For Each rValue In rToFind
FindValues rValue, rSearchRange
Next rValue
End Sub
Public Sub FindValues(ValueToFind As Range, RangeToSearch As Range)
Dim rFound As Range
Dim sFirstAddress
Dim rLastUsedCell As Range
'Find the next available row on the referenced sheet.
With ThisWorkbook.Worksheets(CStr(ValueToFind))
Set rLastUsedCell = .Range("A1", .Cells(.Rows.Count, 1).End(xlUp)).Offset(1)
End With
With RangeToSearch
'Find the first value.
Set rFound = .Find(What:=ValueToFind, _
After:=RangeToSearch.Cells(RangeToSearch.Cells.Count), _
LookAt:=xlPart, _
SearchDirection:=xlNext)
'If the first value exists then remember the address, copy the cells to the
'correct sheet and look for the next row with the same value. Stop when
'it reaches the first address again.
If Not rFound Is Nothing Then
sFirstAddress = rFound.Address
Do
'Parent of RangeToSeach range which will be the Data worksheet.
With .Parent
'Copy columns A:L (columns 1 to 12) and the found cell.
Union(.Range(.Cells(rFound.Row, 1), .Cells(rFound.Row, 12)), rFound).Copy Destination:=rLastUsedCell
End With
Set rLastUsedCell = rLastUsedCell.Offset(1)
Set rFound = .FindNext(rFound)
Loop While rFound.Address <> sFirstAddress
End If
End With
End Sub
Option Explicit
Public Sub Test()
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet, lr1 As Long, lr2 As Long
Dim luArr As Variant, luVal As Variant, r As String, itm As Variant, itmRow As Long
Set ws1 = ThisWorkbook.Worksheets("Data") 'Sheet with data to check for value
Set ws3 = ThisWorkbook.Worksheets("Items") 'LookUp values
luArr = ws3.UsedRange.Columns("A") 'LookUp column
lr1 = ws1.Cells(ws1.Rows.Count, "H").End(xlUp).Row
Dim findRng As Range, copyRng As Range, toRng As Range, fr As Long
Set findRng = ws1.Range("H1:H" & lr1)
On Error Resume Next 'Expected error: sheet not found
Application.ScreenUpdating = False
For Each luVal In luArr
Set ws2 = Nothing
Set ws2 = ThisWorkbook.Worksheets(luVal) 'Copy to
If ws2 Is Nothing Then
Err.Clear
Else
itm = Application.Match(luVal, findRng, 0)
If Not IsError(itm) Then
findRng.AutoFilter Field:=1, Criteria1:="*" & luVal & "*"
fr = IIf(findRng.SpecialCells(xlCellTypeVisible).Cells.Count = 1, 1, 2)
With ws1.UsedRange
Set copyRng = .Range("A" & fr & ":C" & lr1)
Set copyRng = Union(copyRng, .Range("F" & fr & ":F" & lr1))
Set copyRng = Union(copyRng, .Range("H" & fr & ":H" & lr1))
End With
lr2 = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row + 1
copyRng.Copy
ws2.Cells(lr2, 1).PasteSpecial
findRng.AutoFilter
End If
End If
Next
Application.ScreenUpdating = True
End Sub
Sheet1
Items
Before (Sheet A1, A2, and A3)
After
I'm trying to write a macro in VBA that will compare values in two different columns, find the mismatches and then copy and paste the entire row of the mismatched value to a new worksheet. My code is below.
My code works doing this with the individual values (which I commented out below) but when I try to copy and paste the entire row, that's when things don't work.
Public Sub CompareNumber(sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet)
Dim lr1 As Long, lr2 As Long, rng1 As Range, rng2 As Range, c As Range
lr1 = sh1.Cells(Rows.Count, 2).End(xlUp).Row 'Get the last row with data for both list sheets
lr2 = sh2.Cells(Rows.Count, 2).End(xlUp).Row
Set rng1 = sh1.Range("B2:B" & lr1) 'Establish the ranges on both sheets
Set rng2 = sh2.Range("B2:B" & lr2)
For Each c In rng1 'Run a loop for each list, ID mismatches and paste to sheet 3.
If WorksheetFunction.CountIf(rng2, c.Value) = 0 Then
c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)
'sh3.Cells(Rows.Count, 2).End(xlUp)(2) = c.Value
End If
Next
For Each c In rng2
If Application.CountIf(rng1, c.Value) = 0 Then
c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)
'sh3.Cells(Rows.Count, 2).End(xlUp)(2) = c.Value
End If
Next
End Sub
Any help is greatly appreciated!
In the source data is ColumnA always populated? If not that will cause problems when pasting rows to sh3 - an empty cell in colA will cause the next-pasted row to overwrite the previous one.
Something like this is a bit safer (plus a little refactoring to abstract out the repeated loop):
Public Sub CompareNumber(sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet)
Dim rng1 As Range, rng2 As Range, rngDest As Range
'Establish the ranges on both sheets
Set rng1 = sh1.Range(sh1.Range("B2"), sh1.Cells(Rows.Count, 2).End(xlUp))
Set rng2 = sh2.Range(sh2.Range("B2"), sh2.Cells(Rows.Count, 2).End(xlUp))
Set rngDest = sh3.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
CopyMismatches rng1, rng2, rngDest
CopyMismatches rng2, rng1, rngDest
End Sub
Private Sub CopyMismatches(rngSrc As Range, rngMatch As Range, rngDest As Range)
Dim c As Range
For Each c In rngSrc
If Application.CountIf(rngMatch, c.Value) = 0 Then
c.EntireRow.Copy rngDest
Set rngDest = rngDest.Offset(1, 0) '<< safer if could be empty colA values
End If
Next
End Sub
Try
"sh1.rows(c1.row).EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)"
instead of
"c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)"
This may work
How can I modify the following to limit the selection to only start at row 2? Currently it selects every row.
Set myRng = .Range("D2", .Cells(.Rows.Count, "D").End(xlUp))
To make it work, you will have to ensure that there is data in cell D2. See this example.
Sub Sample()
Dim myRng As Range
Dim ws As Worksheet
Dim Lrow As Long
'~~> Change this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Get last row which has data in Col D
Lrow = .Range("D" & .Rows.Count).End(xlUp).row
If Not Lrow < 2 Then
Set myRng = .Range("D2:D" & Lrow)
MsgBox myRng.Address
Else
MsgBox "There is no data in cell D2"
End If
End With
End Sub
This is what I have already, and it works great in removing #N/As from the range. I am now looking to modify it to do the same thing for cells that contain 0.
Sub DeleteErrorRows()
Dim r As Range
Set r = Range("B:B").SpecialCells(xlCellTypeConstants, 16).EntireRow
r.Copy Sheets("Sheet2").Range("A1")
r.Delete
End Sub
Thanks :)
Try this. It autofilters your column and keeps rows that have the findMe value in your source worksheet. You can set it to 0 as I have in the example or to whatever else you want. It copies those rows (except for the header row) to the target sheet and then deletes them from the source sheet.
Note that this also finds the first empty row on the target sheet so that you can run it multiple times without overwriting what you've already moved to the target sheet.
Sub CopyThenDeleteRowsWithMatch()
Dim wb As Workbook
Dim ws As Worksheet
Dim tgt As Worksheet
Dim rng As Range
Dim lastRow As Long
Dim firstPasteRow As Long
Dim findMe As String
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set tgt = wb.Sheets("Sheet2")
lastRow = ws.Range("B" & ws.Rows.Count).End(xlUp).Row
firstPasteRow = tgt.Range("B" & tgt.Rows.Count).End(xlUp).Row + 1
findMe = "0"
Set rng = ws.Range("B1:B" & lastRow)
' filter and delete all but header row
With rng
.AutoFilter Field:=1, Criteria1:="=" & findMe
With .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
.Copy tgt.Range("A" & firstPasteRow)
.Delete
End With
End With
' turn off the filters
ActiveSheet.AutoFilterMode = False
End Sub
Consider:
Sub DeleteZeroRows()
Dim r As Range, rTemp As Range, rB As Range
Set rB = Intersect(Range("B:B"), ActiveSheet.UsedRange)
Set r = Nothing
For Each rTemp In rB
If Not IsEmpty(rTemp) And rTemp.Value = 0 Then
If r Is Nothing Then
Set r = rTemp
Else
Set r = Union(r, rTemp)
End If
End If
Next rTemp
Set r = r.EntireRow
r.Copy Sheets("Sheet2").Range("A1")
r.Delete
End Sub