VBA Help. Delete Rows based on multiple criteria [closed] - vba

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am looking for some VBA help to clean up a Worksheet by deleting rows of data I do not need and keeping the rows of data I do based on multiple criteria.
I want to be able to keep any Row that equals "Subtotal:" in Column A and any Row that contains a number in column C while deleting all other rows that do not match that criteria.
Before Cleanup
Desired Result Requested

I wrote a function which should be able to get the job done.
So you can call the function from a sub and pass the column number you want to test (1 for "A"), the value you would like to test ("" for blank), the name of the worksheet you would like to test. The final argument is a Boolean value and if true it will delete on matching the value in the criteria, if not it will delete on anything else.
Function DeleteCol(iCol As Integer, strCriteria As String, strWSName As String, bPositive As Boolean)
Dim iLastCol As Integer
Dim wsUsed As Worksheet
Set wsUsed = ThisWorkbook.Worksheets(strWSName)
iLastRow = wsUsed.Cells(Rows.Count, iCol).End(xlUp).Row
For i = iLastRow To 1 Step -1
With wsUsed.Cells(i, iCol)
If bPositive Then
If .Value = strCriteria Then .EntireRow.Delete
Else
If .Value <> strCriteria Then .EntireRow.Delete
End If
End With
Next i
End Function
So to do what you requested above you could do:
Sub Delete()
Call DeleteCol(1, "Subtotal:", "CoolSheetName", False)
Call DeleteCol(3, "", "CoolSheetName", True)
End Sub

you may want to try the following (commented) code:
Option Explicit
Sub main()
With Worksheets("MySheetName") '<--| change "MySheetName" to your actual sheet name
With Intersect(.UsedRange, .Columns("A:C"))
.AutoFilter Field:=1, Criteria1:="<>Subtotal" '<--| filter column "A" cells not containing "Subtotal"
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then .Offset(1).Resize(.rows.Count - 1).SpecialCells(xlCellTypeVisible).EntireRow.Delete '<--| delete any filtered cell row
.AutoFilter '<--| show all data back
With .Offset(1, 2).Resize(.rows.Count - 1, 1) '<--| consider column "C" cell from header row (excluded) down
DeleteRows .Cells, xlCellTypeConstants, xlTextValues '<--| delete any "constant text" cell row
DeleteRows .Cells, xlCellTypeFormulas, xlTextValues '<--| delete any "formula text" cell row
DeleteRows .Cells, xlCellTypeBlanks, xlTextValues '<--| delete any "blank" cell row
End With
End With
End With
End Sub
Sub DeleteRows(rng As Range, cellType As XlCellType, cellsValue As XlSpecialCellsValue)
Dim f As Range
Set f = rng.SpecialCells(cellType, cellsValue)
If Not f Is Nothing Then f.EntireRow.Delete
End Sub

Related

Filtering depending upon the column values

I have a sheet FC, with this sheet, I have column R, S and T filled.
I would prefer to have a code, which checks if R contains "invalid" and if S and t are filled, then it should filter complete row.
I know we can use isblank function to check whether the cell is blank or not,
but I am struck how I can use a filter function with these condition .Any help will be helpful for me. I am struck how I can proceed with a vba code. Apologize me for not having a code.
You will have to somehow specify last row:
Dim lastRow, i As Long
For i = 1 To lastRow 'specify lastRow variable
If InStr(1, LCase(Range("R" & i).Value), "invalid") > 0 And Range("S" & i).Value = "" And Range("T" & i).Value = "" Then
'do work
End If
Next i
In our If condition we check three things that you asked.
Try this
Sub Demo()
Dim lastRow As Long
Dim cel As Range
With Worksheets("Sheet3") 'change Sheet3 to your data sheet
lastRow = .Cells(.Rows.Count, "R").End(xlUp).Row 'get last row in Column R
For Each cel In .Range("R5:R" & lastRow) 'loop through each cell in range R5 to lase cell in Column R
If cel.Value = "invalid" And Not IsEmpty(cel.Offset(0, 1)) And Not IsEmpty(cel.Offset(0, 2)) Then
cel.EntireRow.Hidden = True 'hide row if condition is satisfied
End If
Next cel
End With
End Sub
EDIT :
To unhide rows.
Sub UnhideRows()
Worksheets("Sheet3").Rows.Hidden = False
End Sub
Assuming Row1 is the header row and your data starts from Row2, in a helper column, place the formula given below.
This formula will return either True or False, then you may filter the helper column with either True or False as per your requirement.
=AND(R2="Invalid",S2<>"",T2<>"")
In case your header row is different, tweak the formula accordingly.
sub myfiltering()
'maybe first row always 4
firstrow=4
'last, maybe R column alaways have any entered info, so let us see what is the last
lastrow=cells(65000,18).end(xlup).row
'go ahead
for myrow=firstrow to lastrow
if cells(myrow,18)="Invalid" and cells(myrow,19)="" and cells(myrow,20)="" then
Rows(myrow).EntireRow.Hidden = True
else
Rows(myrow).EntireRow.Hidden = false
end if
next myrow
msgbox "Filter completed"
end sub
hope this will help you :)
Why you need the vba code for this problem?
Its more simple if you add a new column with if & and formula, and autofiltering within the added col.
The formula may be similar like this in the U2 cell.
=if(and(R2="invalid";S2="";T2="");"x";"")
Also set autofilter to x. :)

VBA Excel Copy Range from a already autofiltered Range

I have a worksheet containing data. As soon as something changes in a specific column, I want to copy the values of one column in this sheet to another worksheet, but only rows which match some criteria. So I have auto-filtered a range. This works. It only returns rows matching the filter. But from this filtered range, I only need one column. Somehow I cannot get this to work.
So my question would be, how can I only copy a specific column from a filtered range?
Code (snipped) I have so far:
Me.AutoFilterMode = False
With Me.Range("C4:D103")
.AutoFilter Field:=2, Criteria1:="=Marge Only", Operator:=xlOr, Criteria2:="=Contracting"
.SpecialCells(xlCellTypeVisible).Copy Destination:=ThisWorkbook.Worksheets("Result").Range("B5:B104")
End With
ThisWorkbook.SortResult
On Error Resume Next
Me.AutoFilterMode = False
Me.ShowAllData
On Error GoTo 0
The .SpecialCells(xlCellTypeVisible).Copy part copies too much data to the destination worksheet. I need something like:
.Range("A:A").SpecialCells(xlCellTypeVisible).Copy
With .Range("A:A") my thought would be that only column A from the already filtered range would be copied. But this doesn't work.
So what would be your advice how to accomplish this?
You can modify your code slightly to copy only the column you need. This code assumes column A (but you can adjust) and it assumes row 4 is header data (you can also adjust.
With Me
.Range("C4:D103").AutoFilter Field:=2, Criteria1:="=Marge Only", Operator:=xlOr, Criteria2:="=Contracting"
.Range("A5:A103").SpecialCells(xlCellTypeVisible).Copy Destination:=ThisWorkbook.Worksheets("Result").Range("B5")
End With
Is this what you are talking about? It checks column "I" for the criterial then it finds the first and last cells in a filter "A" column and copies the values between the two and paste it in column "O"
Sub copyColumn()
Dim StrRow As Long
Dim str As String
Dim str2 As String
Dim str3 As String
With Sheet1
.AutoFilterMode = False
With .Range("A1:M1")
.AutoFilter
.AutoFilter Field:=9, Criteria1:="dog"
StrRow = Sheets("Sheet1").AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, 2).Row
str = .Range("A" & StrRow).Address
str2 = .Range("A1").End(xlDown).Address
.Range("O2:O" & str3).Value = .Range(str, str2).Value
End With
End With
End Sub

Paste values in dynamic range excel vba

I am writing a script where I want to enable a search in a Database, presenting the results of the search queries in a different worksheet (which I have named Results), so that users do not have access to the whole database at the same time.
In order to do this I want to copy values from the "Database" worksheet into the "Results" worksheet. I have succeeded in selecting the right data from the "Database", in respect to any specific search criteria. I did this with the following code:
With Sheets("Database")
.Range(.Cells(i, 1), .Cells(i, 9)).Copy
End With
Now I want to paste the results into the "Results" spreadsheet and I have done so by writing the following:
Sheets("Results").Range("B600").End(xlUp).Offset(1, 0).PasteSpecial xlPasteFormulasAndNumberFormats
By doing this, I don't quite understand:
if I have strictly defined the paste range as between the first empty row and B600 or;
if I am just defining the beginning of the paste range and, in the case that the search results exceed the 600th row, they will still be pasted after this row.
I ask this because, as the database grows, I will certainly need to guarantee a paste range greater than B600.
I have researched on it but cannot seem to be absolutely sure of what I have done exactly. I must say that I know that the first empty row in the "Results" database will always be 12. In this case, I know that I basically want to paste the search results from the 12th row on. Maybe there is a more straight-forward way to do this.
This is the entire code, for reference:
Private Sub SearchButton_Click()
'This is the search function
'1. declare variables
'2. clear old search results
'3. Find records that match criteria and paste them
Dim country As String
Dim Category As String
Dim Subcategory As String
Dim finalrow As Integer
Dim i As Integer 'row counter
'Erase any entries from the Results sheet
Sheets("Results").Range("B10:J200000").ClearContents
'Deformat any tables in the Results sheet
For Each tbl In Sheets("Results").ListObjects
tbl.Clear
Next
'Define the user-inputed variables
country = Sheets("Results").Range("D5").Value
Category = Sheets("Results").Range("D6").Value
Subcategory = Sheets("Results").Range("D7").Value
finalrow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row
'If statement for search
'For every variable i, start comparing from row 2 until the final row
For i = 2 To finalrow
'If the country field is left empty
If country = "" Then
Sheets("Results").Range("B10:J200000").Clear
MsgBox "You must select a country in order to search the database. Please do so in the drop-down list provided."
Sheets("Results").Range("D5").ClearContents
Sheets("Results").Range("D6").ClearContents
Sheets("Results").Range("D7").ClearContents
Exit Sub
'If the country field is filled in and there results from the search made
ElseIf Sheets("Database").Cells(i, 1) = country And _
(Sheets("Database").Cells(i, 3) = Category Or Category = "") And _
(Sheets("Database").Cells(i, 4) = Subcategory Or Subcategory = "") Then
'Copy the headers of the table
With Sheets("Database")
.Range("A1:I1").Copy
End With
Sheets("Results").Range("B10:J10").PasteSpecial
'Copy the rows of the table that match the search query
With Sheets("Database")
.Range(.Cells(i, 1), .Cells(i, 9)).Copy
End With
Sheets("Results").Range("B600").End(xlUp).Offset(1, 0).PasteSpecial xlPasteFormulasAndNumberFormats
'Hides search form
Me.Hide
End If
Next i
'Toggle Results sheet
Sheets("Results").Activate
'Format results as a table
Set rng = Range(Range("B10"), Range("B10").End(xlUp).SpecialCells(xlLastCell))
Set table = Sheets("Results").ListObjects.Add(xlSrcRange, rng, , xlYes)
table.TableStyle = "TableStyleMedium13"
Range("B11").Select
'Make Excel window visible
Application.Visible = True
End Sub
Thank you very much for your help.
You can count from the bottom of the sheet upto the last used cell in column B, and then OFFSET by 1 row. This prevents you needing to worry about
a) that the range to paste to starts from row 12 (they should contain values), and
b) that you are currently using a hard-coded 'anchor' of B600 which will need updating as the data grows.
Sample code:
Dim ws As Worksheet
Dim rngColumnBUsed As Range
Dim lngFirstEmptyRow As Long
Set ws = ThisWorkbook.Sheets("Results")
Set rngColumnBUsed = ws.Range("B" & ws.Rows.Count).End(xlUp).Offset(1, 0)
lngFirstEmptyRow = rngColumnBUsed.Row
Two ListObjects tblDatabase and tblResults
tblResults data gets cleared
A filter is applied to the second, third and fourth columns of tblDatabase
If there are less than 588 results, we copy the filtered records from tblDatabase to tblResults
If there are more than 588 results then we resize the filtered records' range down to the first 588 records and then copy them to tblResults
We never worry about formatting because tblResults keeps it's original format.
Sub ListObjectDemo()
Dim tblDatabase As ListObject, tblResults As ListObject
Set tblDatabase = Worksheets("Database").ListObjects("tblDatabase")
Set tblResults = Worksheets("Results").ListObjects("tblResults")
If Not tblResults.DataBodyRange Is Nothing Then tblResults.DataBodyRange.ClearContents
With tblDatabase.Range
.AutoFilter Field:=2, Criteria1:="Test A"
.AutoFilter Field:=3, Criteria1:="East"
.AutoFilter Field:=4, Criteria1:="Algeria"
End With
With tblDatabase.DataBodyRange
If .Rows.Count <= 588 Then
.Copy tblResults.ListRows.Add.Range
Else
.Resize(588).Copy tblResults.ListRows.Add.Range
End If
End With
End Sub
Dim searchdata as range, inputfromuser as string
inputfromuser = inputbox("type what you wanna search")
set searchdata = sheets("Database").find(inputfromuser).select
searchdata = activecell.value or activecell.offset(10,5).value
sheets("results").activate
with sheets("result")
range("a12",range("a12").end(xldown)).offset(1,0).select
searchdata.copy destination:= activecell
activecell.offset(1,0).select
end with
Not sure, if I understood you corectly mate.
I dont haveexcel sheet or VBE editor. Just wrote this directly on website. Pls amend as per your need.

vba find first non-blank row

I'm new to VBA and struggling with the piece of code.
I need to find the first non-empty row where the conditions are simultaneously met. There must be text in col B and C and number in col D and G (all 4 conditions must be met).
I'd very grateful for help
s
write like below code using and if & and note:lastrow is end of column values.
for i = 1 to lastrow
if cells(i,"b")<>"" and cells(i,"c")<>"" and isnumber(cells(i,"d"))= true and isnumber(cells(i,"g"))= true then
'do something
end if
next i
you may want to nest SpecialCells() method as follows:
Sub main()
With Worksheets("Conditions") '<--| change "Conditions" to your actual worksheet name
With .Range("B1", .Cells(.Rows.Count, "B").End(xlUp)) '<-- refer to column "B" cells down to last non empty one
With .SpecialCells(XlCellType.xlCellTypeConstants, xlTextValues) '<-- refer to its "text" cells only
With .Offset(, 1).SpecialCells(XlCellType.xlCellTypeConstants, xlTextValues) '<-- refer to adjacent column "text" cells only
With .Offset(, 1).SpecialCells(XlCellType.xlCellTypeConstants, xlNumbers) '<-- refer to adjacent column "number" cells only
With .Offset(, 1).SpecialCells(XlCellType.xlCellTypeConstants, xlNumbers) '<-- refer to adjacent column "number" cells only
MsgBox .Cells(1, 1).row '<--| get first "multifiltered" cells row
End With
End With
End With
End With
End With
End With
End Sub
you may need to add test before each SpecialCells() to check that "current" column actually has some text/numbers value, using a mix of Count() and CountA() method

Search column in Excel, find value, select and delete

Been awhile since I've done some programming and I'm not having much luck with a simple excel vba macro. I have data in a column and i need to select then delete the cells that do not contain a particular value. My data looks like this in a column:
990ppbAu/1,2
990ppbAu/0,5
990ppbAu/0,5
990ppbAu/0,3
9900ppmZr/29,1
9900ppmZn/5,2
9900ppmZn/1
9900ppmZn/0,8
9900ppmZn/0,5
9900ppmCu/2,8
I need to delete the values or strings that do not contain "Au" in them. Here is the start of my code, it's not much and probably wrong...but I'm hoping someone can point me in the right direction:
Option Explicit
Sub SearchColumn()
Dim strAu As String
Dim rngFound, rngDelete As Range
strAu = "*Au*"
'Search Column
With Columns("AF")
'Find values without "Au" in string in column AF and delete.
Set rngFound = .Find(strAu, .Cells(.Cells.Count), xlValues, xlWhole)
If rngFound <> strAu
'Then select the value and delete
'Else move onto the next cell until end of the document
End With
End Sub
I should note, some cells have nothing in them, while some have a string value as seen above. I need it to go through the entire column until end of document. There are about 115,000 records in the table. Thanks in advance!
Edited3 to delete cell content only
edited 2 make it delete single cell
edited to "reverse" the previous filtering criteria and keep cells containing "Au"
if your column has header then you can use this code:
Option Explicit
Sub SearchColumnWithHeader()
Dim strAu As String
strAu = "Au"
With ActiveSheet
With .Range("AF1", .Cells(.Rows.Count, "AF").End(xlUp))
.AutoFilter Field:=1, Criteria1:="<>*" & strAu & "*"
If Application.WorksheetFunction.Subtotal(103, .Cells) > 1 Then .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).ClearContents
End With
.AutoFilterMode = False
End With
End Sub