Deleting Rows that contain criteria in specific columnn - excel

Quick question.
I have this macro below which looks if column B contains a 0 value. In the instance that it does, it deletes that row. This works well until there are instances where no rows contain a zero, and then it throws an error saying it's out of range.
is it possible to tweak this so that it runs without an error, and just doesn't delete anything if it can't find a row with a 0 in Column B?
Sub Deletezero()
Dim LastRow As Long, ReadRow As Long, n As Long
With ThisWorkbook.Sheets("Sheet1")
LastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
End With
ReadRow = 1
For n = 1 To LastRow
If Range("B" & ReadRow).Value Like "*0*" = True Then
Range("H" & ReadRow).EntireRow.Delete
Else
ReadRow = ReadRow + 1
End If
Next
End Sub

Please, try the next code. It should be faster then yours, deleting all rows (if any to be deleted) at once, at the end. In fact, the code only select the rows. If the selection is correct, please replace Select with Delete:
Sub Deletezero()
Dim sh As Worksheet, LastRow As Long, n As Long, rngDel As Range
Set sh = ThisWorkbook.Sheets("Sheet1")
LastRow = sh.cells(sh.rows.count, "B").End(xlUp).row
For n = 1 To LastRow
If sh.Range("B" & n).Value Like "*0*" Then
If rngDel Is Nothing Then
Set rngDel = sh.Range("B" & n)
Else
Set rngDel = Union(rngDel, sh.Range("B" & n))
End If
End If
Next
If Not rngDel Is Nothing Then rngDel.EntireRow.Select 'if it selects what you need, please replace Select with Delete
End Sub

Related

Trying to loop through column B and if two cells in a row contain the same text then delete the first ones entire row and keep the second

Need to loop through column B and if the cell contains the text in in quotes then need to delete the entire row of the first one and keep the second. Keep getting with block error
Dim i As Long
Dim rng As Range
rng = Sheets("Sheet1").Range("B" & Rows.Count).End(xlUp).Row
For i = 1 To rng
If Cells(i, 1).Value = "FINANCE SYSTEM OF GREEN BAY, INC." And Cells(i, 1).Offset(1, 0).Value = "FINANCE SYSTEM OF GREEN BAY, INC." Then
Cells(i, 1).EntireRow.Delete
End If
Next i
As stated above, deletion during the iteration from small to bigger is wrong, as the bad variable declaration. You can iterate backwards, but the best solution is to not delete a row at a time. Using a Union range and deleting its rows at the end is the fastest way:
Sub deleteRowsAtOnce()
Dim sh As Worksheet, i As Long, lastRow As Long, rngDel As Range
Set sh = Sheets("Sheet1")
lastRow = sh.Range("B" & sh.rows.count).End(xlUp).row
For i = 1 To lastRow
If sh.cells(i, 1).value = "FINANCE SYSTEM OF GREEN BAY, INC." And _
sh.cells(i, 1).Offset(1, 0).value = "FINANCE SYSTEM OF GREEN BAY, INC." Then
If rngDel Is Nothing Then
Set rngDel = sh.cells(i, 1)
Else
Set rngDel = Union(rngDel, sh.cells(i, 1))
End If
End If
Next i
If Not rngDel Is Nothing Then rngDel.EntireRow.Delete
End Sub
Apart from your definition of rng as pointed out by #Bigben you are making the classic mistake of changing a range whilst you are iterating over it.
When you delete a row the number of rows reduces by 1. But VBA doesn't know this so the rng variable isn't automatically adjusted. The usual symptom is that some lines are not deleted or an index error. To do the deletions without affecting the yet to processed remainder of the range you need to iterate backwards, from Rng to 1 step -1.
Delete Rows (Backward Loop)
Option Explicit
Sub KeepTheSecond()
Const wsName As String = "Sheet1"
Const Col As String = "B"
Const CritString As String = "FINANCE SYSTEM OF GREEN BAY, INC."
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim LastRow As Long: LastRow = ws.Range(Col & ws.Rows.Count).End(xlUp).Row
Dim r As Long
For r = LastRow - 1 To 1 Step -1
If StrComp(ws.Cells(r, Col).Value, CritString, vbTextCompare) = 0 Then
If StrComp(ws.Cells(r, Col).Offset(1).Value, CritString, _
vbTextCompare) = 0 Then
ws.Cells(r, Col).EntireRow.Delete
End If
End If
Next r
End Sub

Insert Row when 2 conditions are met

I have created below code which works like IF Col"B" any cell <> "" And Col"L" any cell = "Leop" then add row below to the active cell.
I mean I'm trying to achieve is to insert single row after certain row which contain in column B any value, and if column L in same row contains value = "Leop". Then add the row after that certain row.
But an error is appear. Compile Error: Invalid use of property on xlDown
Your help will be appreciated to fix it.
From this:
to this:
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long
Dim rng As Range
Dim rng2 As Range
Dim i As Long
Dim p As Long
Dim dat As Variant
Dim datt As Variant
Dim IRow As Long
Set ws = Thisworkbooks.Sheets("Sheet2")
With ws
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("B2:B" & LRow)
Set rng2 = .Range("L2:L" & LRow)
dat = rng
datt = rng2
IRow = Selection.Row
For i = LBound(dat, 1) To UBound(dat, 1)
For p = LBound(datt, 1) To UBound(datt, 1)
If dat(i, 1) <> "" And datt(p, 1) = "Leop" Then
Rows(IRow + 1).Select
Selection.Insert Shift: xlDown
End If
End Sub
It will be like in formula:
IF(AND(B2<>"",L2="Leop"),"InsertRowBelow to Row 2 If condition is met","")
and will drag it down to the lastRow.
Thisworkbooks.Sheets("Sheet2") should be Thisworkbook.Sheets("Sheet2") and missing = in Selection.Insert Shift:= xlDown
Inserting or deleting rows will change the last row number so start at the bottom and work upwards.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet, LRow As Long, r As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
LRow = .Range("B" & .Rows.Count).End(xlUp).Row
For r = LRow To 2 Step -1
If .Cells(r, "B") <> "" And .Cells(r, "L") = "Leop" Then
.Rows(r + 1).Insert shift:=xlDown
n = n + 1
End If
Next
End With
MsgBox n & " rows inserted", vbInformation
End Sub
Try this with autofilter, you dont have to loop through each row. So it will work faster for larger data.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long, cl As Range
Set ws = ThisWorkbook.Sheets("Sheet2")
LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("L1:L" & LRow).AutoFilter 1, "Leop"
For Each cl In ws.Range("_FilterDatabase").SpecialCells(12).Cells
If ws.Range("B" & cl.Row) <> "" Then
cl.Offset(1).EntireRow.Insert Shift:=xlDown
End If
Next
ws.AutoFilterMode = False
End Sub

Excel VBA, Check values from columns between sheets and delete duplicate

I need some help with comparing values from one column to another and delating it.
so far I have this:
Sub DelateDuplicates()
delArray = Sheets("Save").Range("B1:B") ' saved values
toDelate = Sheets("Validation").Range("B2:B").Value ' values to be checked and delated
lastRow = toDelate.Range("B1000").End(xlUp).Row ' last row
Firstrow = toDelate.Range("B2").End(xlDown).Row ' First row
Dim i As Long
For Lrow = lastRow To Firstrow Step -1
With Worksheets("Validation").Cells(Lrow, "A")
For i = 0 To UBound(delArray) ' arrays are indexed from zero
If Not IsError(.Value) Then
If .Value = delArray(i) Then
.EntireRow.Delete
Exit For
End If
End If
Next
End With
Next Lrow
End Sub
And I do have an error.
"1004 "Application-defined or Object-defined error" "
I have spent 2 days trying to figure it out so far no luck.
Any help will be appreciated.
I modified your code little bit. You can define your first rows and last row the want you want, I have kept it simple for the sake of concept
Option Explicit
Sub DelateDuplicates()
Dim Lrow As Long
Dim delarray()
With Worksheets("Save")
delarray = .Range("B1:B" & .Cells(.Rows.Count, "B").End(xlUp).Row).Value
End With
Dim i As Long
Dim lastrow As Long
Dim firstrow As Long
firstrow = 1
With Worksheets("Validation")
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Lrow = lastrow To firstrow Step -1
For i = 1 To UBound(delarray)
If Not IsError(.Cells(Lrow, "A").Value) Then
If .Cells(Lrow, "A").Value = delarray(i, 1) Then
.Cells(Lrow, "A").EntireRow.Delete
Exit For
End If
End If
Next i
Next Lrow
End With
End Sub
You can avoid loops within loops by using a Dictionary Object
Option Explicit
Sub DeleteDuplicates()
Dim wsSave As Worksheet, wsValid As Worksheet
Dim iLastRow As Long, iFirstRow As Long, i As Long, n As Long
Dim dict As Object, key, cell As Range
With ThisWorkbook
Set wsSave = .Sheets("Save")
Set wsValid = Sheets("Validation")
End With
Set dict = CreateObject("Scripting.Dictionary")
' get values to delete from Column B
For Each cell In wsSave.Range("B1", wsSave.Cells(Rows.Count, "B").End(xlUp))
key = Trim(cell)
If Len(key) > 0 Then
dict(key) = cell.Row
End If
Next
' scan Validation sheet and delete matching from Save
With wsValid
iFirstRow = .Cells(2, "B").End(xlDown).Row
iLastRow = .Cells(Rows.Count, "B").End(xlUp).Row
For i = iLastRow To iFirstRow Step -1
key = .Cells(i, "A")
If dict.exists(key) Then
.Rows(i).Delete
n = n + 1
End If
Next
End With
' resutl
MsgBox n & " rows deleted between row " & _
iFirstRow & " and " & iLastRow, vbInformation
End Sub

Cannot insert rows above range?

i wrote the following code, in order to paste the rngtocopy ABOVE rngins....
Now ive tried around a lot and it keeps adding it below the rngins and i have no idea why.
I tried out xlshiftup, which actually gives me errors, probably cause there are values above?
Sub reviewverschieben()
Dim counter As Long, lrow As Long, lrowrev As Long, i As Long, lastrev As Long
Dim ws As Worksheet
Dim rngtocopy As Range, rngins As Range
Dim lastcolumn As String
Set ws = ActiveSheet
Rows.EntireRow.Hidden = False
counter = 0
With ws
lrow = .Cells(Rows.Count, 1).End(xlUp).row
Do While counter = 0
For i = 32 To lrow
If .Cells(i, 1).Value = "Review Participants" And counter = 1 Then
lrowrev = i
ElseIf .Cells(i, 1).Value = "Review Participants" And i <> lrow Then
counter = counter + 1
lastrev = i 'row nr which we take as a reference to insert new table above
lrowrev = lastrev
lcol = .Cells(i + 1, .Columns.Count).End(xlToLeft).Column 'last meeting of the review is our reference for lastcol
ElseIf counter = 1 And i = lrow Then
lrowrev = lrow + 2
Exit For
End If
Next
Loop
lastcolumn = Split(Cells(, lcol).Address, "$")(1)
Set rngtocopy = .Range("A" & 32 & ":" & lastcolumn & lrowrev)
Debug.Print rngtocopy.Address
Set rngins = .Range("A" & 32 & ":" & lastcolumn & lrowrev)
Debug.Print rngins.Address
'Range("A" & lrow).Offset(5).EntireRow.Hidden = False
rngtocopy.Copy
rngins.Insert Shift:=xlShiftDown
ringins.PasteSpecial Paste:=xlPasteAll
Image for better clarification, what i have right now
If you need to make space for copying of rngins range you should proceed as following:
Dim aboveR As Long
aboveR = rngins.Cells(1, 1).row
sh.Rows(aboveR & ":" & aboveR + rngtocopy.Rows.Count - 1).Insert xlDown
This piece of code will insert above the rngins range as many rows as rngtocopy range has.
If you need to insert only some rows of the range, the second parameter will need to replace rngtocopy.Rows.Count with that specific number of rows. And then, the paste cell must be determined by adding that number to the existing aboveR value:
Dim pasteCell As Range
Set pasteCell = sh.Range("A" & aboveR + rngtocopy.Rows.Count)
rngtocopy.Copy pasteCell
And in order to make your code working in the way you wanted, try this:
rngtocopy.Copy
rngins.Cells(1, 1).Insert Shift:=xlDown
Application.CutCopyMode = False 'Clear clipboard
When you try to insert rows and there is something in clipboard, the clipboard content is inserted...
Your specification of RngIns may well be described as adventurous, considering this little piece of code juggling: lastcolumn = Split(Cells(, lcol).Address, "$")(1). I recommend that you define the range like this.
Set rngIns = .Range(.Cells(32, "A"), .Cells(lrowrev, lcol))
The code defines the first and last cells of the range and that makes it easy for you to follow. Now, if you insert at rngIns the insertion will be made below that range. If you insert at RngIns.Offset(1) the insertion will be made above rngIns. Of course, you can make that same difference by defining rngIns's row differently, perhaps like Set rngIns = .Range(.Cells(33, "A"), .Cells(lrowrev + 1, lcol)).
However, I wonder why you insert cells at all. Wouldn't it be easier to insert so many sheet rows and then paste to the blank rows?

VBA insert rows_dynamic

Below is the piece of code in VBA which basically insert no of rows based on a count present in a specific cell, Now I want to change the code so that no of rows that will be inserted is to be one less then the count present in a specific cell.
for eg- if in a specific column and specific cell count=N then macro will runn and add N no of rows.Now I want rows is to be added is one less i.e N-1
Sub InsertRowsIf()
Dim lr As Long, R As Range, i As Long
lr = Range("R" & Rows.Count).End(xlUp).Row
Set R = Range("R3", "R" & lr)
Application.ScreenUpdating = False
For i = R.Rows.Count To 1 Step -1
If IsNumeric(R.Cells(i, 1).Value) And Not IsEmpty(R.Cells(i, 1)) Then
R.Cells(i, 1).Offset(1, 0).Resize(R.Cells(i, 1).Value).EntireRow.Insert
End If
Next i
End Sub
I think by trying to insert the use of R as a Range is causing issues. It is not needed.
Sub InsertRowsIf()
Dim ws As Worksheet
Set ws = Worksheets("Sheet1") ' Change to your sheet
Dim lr As Long
lr = ws.Range("R" & Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
Dim i As Long
For i = lr To 3 Step -1
If IsNumeric(ws.Cells(i, 18).Value) And ws.Cells(i, 18) <> "" Then
ws.Cells(i, 1).Offset(1,0).Resize(ws.Cells(i, 18).Value - 1).EntireRow.Insert
End If
Next i
Application.ScreenUpdating = True
End Sub
You forgot to turn ScreenUpdating back on. Updated code to skip last row and applied standard indentation.
Option Explicit
Sub InsertRowsIf()
Dim lr As Long, R As Range, i As Long
lr = Range("R" & Rows.Count).End(xlUp).Row
Set R = Range("R3:R" & lr - 1)
Application.ScreenUpdating = False
For i = R.Rows.Count To 1 Step -1
If IsNumeric(R.Cells(i, 1).Value) And Not IsEmpty(R.Cells(i, 1)) Then
R.Cells(i, 1).Offset(1, 0).Resize(R.Cells(i, 1).Value).EntireRow.Insert
End If
Next i
Application.ScreenUpdating = True
End Sub

Resources