Delete Table Row Based on Criteria VBA - excel

I am attempting to delete a specific table row based on values in two columns. I attempted to apply filters to the table columns to narrow my criteria, but once I click delete, the ENTIRE ROW is deleted causing values outside of the table to be deleted. Also, the macro recorder isn't as dynamic as I'd like it to be, since it ONLY selects the cell I clicked while recording.
Sub Macro2()
'
' Macro2 Macro
'
'
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:= _
"Apple" \\Narrowing criteria in Column 1 of the table
Range("A4").Select \\This only applies to a specific cell, and the value can shift
Selection.EntireRow.Delete \\This will delete the entire sheet row, I'd like for only the table row to be deleted
Range("A5").Select
Selection.EntireRow.Delete
Selection.EntireRow.Delete
End Sub
Is there a way to find the desired string in a column and delete only the rows in the table once the criteria is met? I attempted to only delete the ListObject.ListRows, but it only references the row I've selected, and not the one based off criteria.

You could use .DataBodyRange and .SpecialCells(xlCellTypeVisible) to set a range variable equal to the filtered ranges, then unfilter and delete:
Dim dRng As Range
With ActiveSheet.ListObjects("Table1")
.Range.AutoFilter Field:=1, Criteria1:="Apple"
If WorksheetFunction.Subtotal(2, .DataBodyRange) > 0 Then
Set dRng = .DataBodyRange.SpecialCells(xlCellTypeVisible)
.Range.AutoFilter
dRng.Delete xlUp
End If
End With

You will have to indicate which cells/range you want to delete. You can find the relevant row by using the find function. Since your table is static I would propose the following macro.
A for loop checking each row is also possible, but not so efficient for a very large table. It can be useful to prepare your dataset by adding a flag to column c (e.g. a 1 if to be deleted).
EDIT suggestion by Tate also looks pretty clean
Sub tabledelete()
Dim ws As Worksheet
Dim rangecheck As Range
Dim rcheck As Integer
Set ws = Sheets("Sheet1") 'fill in name of relevant sheet
Set rangecheck = Range("A1") ' dummy to get the do function started
Do While Not rangecheck Is Nothing
With ws
With .Range("C2:C30") ' fill in relevant range of table
Set rangecheck = .Find(what:=1, LookAt:=xlWhole)
End With
If Not rangecheck Is Nothing Then 'only do something if a 1 is found
rcheck = rangecheck.Row
.Range(.Cells(rcheck, 1), .Cells(rcheck, 3)).Delete Shift:=xlUp 'delete 3 columns in row found
End If
End With
Loop
End Sub

Related

error while deleting a sheet row Runtime error '1004': Delete method of range class failed

I'm using excel vba to delete filtered rows. The code is working just when I specified the range to be on A1 and put my table headers on A1. But, my table headers on B9 so I need to put it on the range but that error occurs. I didn't know why its working for Range("A1") and it didn't work for Range("B9"). In addition when I put A1 as my range to my table it deleted all the rows not just the filtered rows.
Sub Delete_CD_Blanks()
Dim Rng As Range
Dim Rng_Del As Range
Set Rng = Range("B9").CurrentRegion
If Sheets("tt").AutoFilterMode = True Then
Sheets("tt").AutoFilter.ShowAllData
End If
' Rng.AutoFilter field:=4, Criteria1:=” = ”
Rng.AutoFilter field:=6, Criteria1:="??? ?????"
Rng.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
Sheets("tt").AutoFilterMode = False
End Sub
You did not ask my clarification questions and I (only) suppose that your problem stays in the fact that there are some cells above the 9th row, which make part from the CurrentRegion. If I am right, please add a code line, able to create a range starting from 9th row (inclusive):
'your existing code
Set rng = Range("B9").CurrentRegion 'existing in your code
Set rng = Intersect(rng, ActiveSheet.rows("9:" & rng.rows.count)) 'it creates a range slice, starting from 9th row and ending to the `CurrentRegion` last row
'your existing code

excel vba copy and paste to fix "#REF" cells

I'm trying to make a checkbook register on excel 365. I am trying to add the feature of deleting a row(transaction) but when I run my vba code it errors out with the following: Run-time error '1004': Paste method of worksheet class failed.
When I run my code to delete a row the balance column fills up with "#REF". My effort to fix this by copying the balance column and pasting it back after the row is deleted isn't working. Balance column still fills up with "#REF"s. Here is the code i'm using to copy and paste the balance column:
Sub DeleteTransactionRectangle_Click()
Dim deletedRow
Dim rng As Range
Set rng = Selection
deletedRow = rng.Row
MsgBox (deletedRow)
Worksheets("Register").Range("I:I").Copy
rng.EntireRow.Delete
ActiveSheet.Paste Destination:=Worksheets("Register").Range("I:I")
End Sub
Anyone have any ideas to make this work.
You have dim 'rngg' but set 'rng' - should these not both be the same?
When you delete the row, it seems the copied information is lost from the clipboard. Instead, you could copy the formula from column I in the preceding row, and paste it back into the row you deleted:
rng.EntireRow.Delete
ActiveSheet.Range("I" & deletedRow - 1).Copy
ActiveSheet.Range("I" & deletedRow).Select
ActiveSheet.Paste
Deleting Rows Containing Formulas
Tip
In design mode, right-click on the command button and select Properties. Change TakeFocusOnClick to False, so when you click the command button it doesn't get selected (focus) but the selection on your sheet stays the same.
Formula
Your formula turns out to be bad when deleting rows. You could change it to:
=SUM(H$1:H2)-SUM(F$1:F2)
which is 'deleting columns proof'.
Improve Code
To Study
Range.Find
method
Areas object
Range.Areas property
Range.Resize property
Application.Union method
Application.Intersect method
Change the values in the constants section to fit your needs.
Option Explicit
Sub DeleteTransactionRectangle_Click()
Const rowFR As Long = 2 ' First Row of Data
Const colFR As Long = 9 ' Formula Column
Dim rowLR As Long ' Last Row of Data
Dim rng As Range ' Current Area (For Each Control Variable)
Dim rngTransAction As Range ' Transaction (Column) Range
Dim rngUnion As Range ' Union Range
Dim rngFinal As Range ' Intersection (Final) Range
' Calculate Last Row of Data.
rowLR = Columns(colFR).Find(What:="*", LookIn:=xlFormulas, _
SearchDirection:=xlPrevious).Row
' From the selection, create Union Range which only contains cells
' of Formula Column, which will later be compared
' to Transaction (Column) Range.
For Each rng In Selection.Areas
If Not rngUnion Is Nothing Then
Set rngUnion = Union(rngUnion, Cells(rng.Row, colFR) _
.Resize(rng.Rows.Count))
Else
Set rngUnion = Cells(rng.Row, colFR).Resize(rng.Rows.Count)
End If
Next
' Define Transaction (Column) Range.
Set rngTransAction = Cells(rowFR, colFR).Resize(rowLR - rowFR + 1)
' Create Intersection (Final) Range which will 'eliminate'
' all 'non-valid' areas of the Selection Range. 'Non-valid' areas are
' the ones before First Row of Data and after Last Row of Data.
If Not rngUnion Is Nothing Then Set rngFinal _
= Intersect(rngUnion, rngTransAction)
' Delete rows of Intersection (Final) Range.
If Not rngFinal Is Nothing Then rngFinal.EntireRow.Delete
End Sub

combobox, how do i exclude blanks from list retrieved via listobject

Trying to apply data to a combobox, which works out great, except it also include filtered values.
i filter on field 1, filter by a number, there are several empty cells in this row,
those with empty cells in field1 i dont want to see this time.
I pupulate the databodyrange value from column 13 into the combobox list, however even when filtered correctly
it also adds the rows i filtered away.
code..
Private Sub UserFrom_Initialize()
Dim db As ListObject
Set db = Worksheets("baseOfData").ListObjects("database")
db.Range.AutoFilter Field:=1, Criteria1:="<>"
Me.cmbTasks.List = db.ListColumns(13).DataBodyRange.Value
End Sub
I can solve it by running a for loop, and checking every cell before adding it
but that would kinda defeat the purpose of doing it all with 2 lines of code.
any suggestions
however even when filtered correctly it also adds the rows i filtered away.
Me.cmbTasks.List = db.ListColumns(13).DataBodyRange.Value
That is because you are incorrectly doing it. You are referring to complete column and not the filtered range. Try this
Dim db As ListObject
Set db = Worksheets("baseOfData").ListObjects("database")
db.Range.AutoFilter Field:=1, Criteria1:="<>"
Me.cmbTasks.List = db.DataBodyRange.Columns(13).SpecialCells(xlCellTypeVisible).Value
The next problem that you may face will be that it will show values from the first Area only if there are multiple areas.
To handle this, try
Dim db As ListObject
Dim aCell As Range, rngArea As Range
Set db = Worksheets("baseOfData").ListObjects("database")
db.Range.AutoFilter Field:=1, Criteria1:="<>"
'~~> Loop through each area
For Each rngArea In db.DataBodyRange.Columns(13).SpecialCells(xlCellTypeVisible).Areas
'~~> Loop though each cell in the area
For Each aCell In rngArea
cmbTasks.AddItem aCell.Value
Next aCell
Next rngArea
Why not a little simpler (if iteration is an option):
Dim db As ListObject, cel As Range
Set db = Worksheets("baseOfData").ListObjects("database")
For Each cel In db.DataBodyRange.Columns(13).Cells
If cel.EntireRow.Hidden <> True Then
cmbTasks.AddItem cel.value
End If
Next
Would you like to do some modifications on the table, according to selected combo value? If yes, the real row number associated to each combo value must be memorized. In a hidden column of the combo, for instance (using cel.Row).

Move all non-blank rows to the top of the ws fast

I'm trying to move all non blank rows to the top of my worksheet (actually to the top of an Autofilter).
I have realised that simply deleting the blank rows is quite slow, and that a faster alternative is assigning the range to a variant.
I have come up with this code, however for some reason it's losing some of the rows:
Public Sub CompactRows(ByRef ws As Worksheet)
Dim a As Variant
With ws
a = .AutoFilter.Range.Offset(1, 0).Columns(1).SpecialCells(xlCellTypeConstants).EntireRow
.AutoFilter.Range.Offset(1, 0).Clear
.AutoFilter.Range.Cells(2, 1).Resize(UBound(a), .UsedRange.Columns.Count) = a
End With
End Sub
So if I have 1000 rows, separated by blank rows, creating 100 sub-ranges, after the function ends I only have 100 rows (the other 900 are lost).
I noticed that in this case Ubound(a) also returns 100. My theory is that it copies only the first row in each sub-range but I'm not sure. Any solution to this, or another faster alternative to achieve the same result quickly will be greatly appreciated.
Sorting it to find the blanks shouldn't affect the rest of the rows - they should stay in the correct order. However, if you end up sorting on more than one column because what constitutes a blank row is more complicated, then it could happen.
This procedure takes a range with no headers. It adds a column with the original sort, sorts the range, deletes the blanks, then resorts the range back to the original way.
Public Sub CompactRows(ByRef rng As Range)
Dim rNew As Range
'Put the row in a column so you can sort it
'back to the original way later
With rng.Offset(, rng.Columns.Count).Resize(, 1)
.Formula = "=ROW()"
.Copy
.PasteSpecial xlPasteValues
End With
'Make a range that includes the sort column
Set rNew = rng.Resize(, rng.Columns.Count + 1)
'Sort on the first column to get all the blanks together
rNew.Sort rNew.Cells(1), xlAscending, , , , , , xlNo
'Assume a blank in column 1 is a blank row - delete them all in one shot
rNew.Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
'Resort the range on the sort column
rNew.Sort rNew.Cells(rNew.Columns.Count), xlAscending, , , , , , xlNo
'Delete the sort column
rNew.Cells(rNew.Columns.Count).EntireColumn.Delete
End Sub
As ExcelHero said, you can sort the rows from Excel. But this will change the order of your non-empty rows. IF you want to remove blank rows but keep the order of your data, you can apply this macro:
Sub removeEmptyRows()
Dim r As Range
For Each r In UsedRange.Rows
If Application.CountA(r) = 0 Then r.Delete
Next
End Sub

Insert Value into cells that are in a table column after a filter

Not sure why my code isn't working. I am filtering a column in a table by blank values "(blanks)". Then inserting the value "NA" into the first cell and copying that value by dragging down the fill handle down to last cell in the column. Then unfiltering table again so everything is showing.
But when I run the macro all it does is copy the column header name and pastes it in the first cell and nothing else.
Sub InsertNAtoBlanks()
'
' InsertNAtoBlanks Macro
'
'
ActiveSheet.ListObjects("Table6").Range.AutoFilter Field:=11, Criteria1:= _
"="
Range("K4").Select
ActiveCell.FormulaR1C1 = "NA"
Range("K4").Select
Selection.FillDown
ActiveSheet.ListObjects("Table6").Range.AutoFilter Field:=11
End Sub
Looks like you used the macro recorder to getthis code. While macro recorder is a good way to see what objects to use, it can produce some pretty awfull code!
Try this strategy instead
Sub Demo()
Dim lo As ListObject
Dim rng As Range
Set lo = ActiveSheet.ListObjects("Table6")
Set rng = lo.DataBodyRange.Columns(11)
rng.SpecialCells(xlBlanks) = "NA"
End Sub
Or reference the columns by name
Set rng = lo.ListColumns("YourColumnName").DataBodyRange

Resources