I need to filter a data table where 3 columns can contain the result I am looking for:
So if the criteria is found in columns 1, 2 or 3 then the row should be returned.
(source: gulfup.com)
So in the above sample data lets say I select the criteria as "Fat"
I am looking for the autofilter to return rows 1 & 2; if I select the criteria as "Funny" I need rows 2 & 6 and so on....
Below is my code which is not working since apparently it tries to find the rows in which all columns contain the criteria, and it is not what I am looking to do.
With Sheet1
.AutoFilterMode = False
With .Range("A1:D6")
.AutoFilter
.AutoFilter Field:=2, Criteria1:="Fat", Operator:=xlFilterValues
.AutoFilter Field:=3, Criteria1:="Fat", Operator:=xlFilterValues
.AutoFilter Field:=4, Criteria1:="Fat", Operator:=xlFilterValues
End With
End With
I have also tried to use Operator:=xlor but when I ran the code it returned no results.
In short: The row must be returned by the filter is the criteria is found in column B or C or D.
Help is definitely appreciated.
As follow up from comments, there are two ways for you.
Use additional column with formula:
Dim copyFrom As Range
With Sheet1
.AutoFilterMode = False
With .Range("A1:E6")
'apply formula in column E
.Columns(.Columns.Count).Formula = "=OR(B1=""Fat"",C1=""Fat"",D1=""Fat"")"
.AutoFilter Field:=5, Criteria1:=True
On Error Resume Next
Set copyFrom = .Offset(1).Resize(.Rows.count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End With
End With
If Not copyFrom Is Nothing Then copyFrom.EntireRow.Copy
Use For loop with Union:
Dim copyFrom As Range
Dim i As Long
With Sheet1
For i = 2 To 6
If .Range("B" & i) = "Fat" Or .Range("C" & i) = "Fat" Or .Range("D" & i) = "Fat" Then
If copyFrom Is Nothing Then
Set copyFrom = .Range("B" & i)
Else
Set copyFrom = Union(.Range("B" & i), copyFrom)
End If
End If
Next
End With
If Not copyFrom Is Nothing Then copyFrom.EntireRow.Copy
For copying also header:
Dim copyFrom As Range
Dim i As Long
With Sheet1
Set copyFrom = .Range("B1")
For i = 2 To 6
If .Range("B" & i) = "Fat" Or .Range("C" & i) = "Fat" Or .Range("D" & i) = "Fat" Then
Set copyFrom = Union(.Range("B" & i), copyFrom)
End If
Next
End With
copyFrom.EntireRow.Copy
UPDATE:
Dim hideRng As Range, copyRng As Range
Dim i As Long
Dim lastrow As Long
With Sheet1
lastrow = .Cells(.Rows.Count, "B").End(xlUp).Row
.Cells.EntireRow.Hidden = False
For i = 2 To lastrow
If Not (.Range("B" & i) = "Fat" Or .Range("C" & i) = "Fat" Or .Range("D" & i) = "Fat") Then
If hideRng Is Nothing Then
Set hideRng = .Range("B" & i)
Else
Set hideRng = Union(.Range("B" & i), hideRng)
End If
End If
Next
If Not hideRng Is Nothing Then hideRng.EntireRow.Hidden = True
On Error Resume Next
Set copyRng = .Range("B1:B" & lastrow).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End With
If copyRng Is Nothing Then
MsgBox "There is no rows matching criteria - nothing to copy"
Exit Sub
Else
copyRng.EntireRow.Copy
End If
Related
So the situation is that I would like to copy 4 columns with variable lengths into one column containing all the data from these 4. The problem is I loose data in the process.
As an example it should be 693 rows but I only get 648 rows all in all.
I'm relatively new to VBA and have come up with these lines of code.
Sub Copy()
Dim RngA As Range, RngB As Range, RngC As Range, RngD As Range, Rng As Range
Set RngA = Range(Range("I2"), Range("I" & Rows.Count).End(xlUp))
Set RngB = Range(Range("J2"), Range("J" & Rows.Count).End(xlUp))
Set RngC = Range(Range("K2"), Range("K" & Rows.Count).End(xlUp))
Set RngD = Range(Range("L2"), Range("L" & Rows.Count).End(xlUp))
Range("O2").Resize(RngA.Count).Value = RngA.Value
Range("O" & RngA.Count + 1).Resize(RngB.Count).Value = RngB.Value
Range("O" & RngB.Count + 1).Resize(RngC.Count).Value = RngC.Value
Range("O" & RngC.Count + 1).Resize(RngD.Count).Value = RngD.Value
With Sheets("Keywords")
Columns("O:O").Sort Key1:=.Range("=O1"), Order1:=xlAscending, Header:=xlYes
End With
End Sub
See my comment above, but here is an alternative approach using arrays which saves having to set up multiple similarly-named range variables.(Btw am assuming everything is on the Keywords sheet.)
Sub Copy()
Dim vRng(1 To 4) As Range, i As Long
With Sheets("Keywords")
For i = LBound(vRng) To UBound(vRng)
Set vRng(i) = .Range(.Cells(2, i + 8), .Cells(.Rows.Count, i + 8).End(xlUp))
Next i
For i = LBound(vRng) To UBound(vRng)
.Range("O" & Rows.Count).End(xlUp)(2).Resize(vRng(i).Count).Value = vRng(i).Value
Next i
.Columns("O:O").Sort Key1:=.Range("O1"), Order1:=xlAscending, Header:=xlYes
End With
End Sub
Sub test_calculateval()
Dim rnData, r As Range, ThisYearID, LR, FR, EndR, HomeCount, AwayCount, DrawCount, i As Long, Hometeam As String
ThisYearID = Sheet5.Cells(2, 1).Value - 1
Hometeam = Sheet5.Cells(2, 5)
HomeCount = 0
With Sheet1
Set rnData = Range(Range("A2"), Range("R2").End(xlDown))
With rnData
Rows("1:1").Select
Selection.AutoFilter
ActiveSheet.Range(Range("A2"), Range("R2").End(xlDown)).AutoFilter Field:=1, Criteria1:=">" & ThisYearID - 5
ActiveSheet.Range(Range("A2"), Range("R2").End(xlDown)).AutoFilter Field:=5, Criteria1:=Hometeam
LR = Range("A" & Rows.count).End(xlUp).Row
Set r = ActiveSheet.Range("A2:R" & LR).Rows.SpecialCells(xlCellTypeVisible)
FR = r.Row
EndR = Range("A" & FR).End(xlDown).Row
For Each rngarea In .SpecialCells(xlCellTypeVisible).Areas
If Range("K2:K" & LR).SpecialCells(xlCellTypeVisible).Value = "H" Then
HomeCount = HomeCount + 1
End If
Next
End With
End With
MsgBox HomeCount
End Sub
I want to check if each cell in column K (after filtering) is equal to "H", and count them.
This code is throwing a type mismatch error, what seems to be the problem
Since it is possible that
Range("K2:K" & LR).SpecialCells(xlCellTypeVisible).Value
might be returning multiple cells, so it cannot be compared to a single string value. In simple words, we cannot calculate the value of multiple cells, when they are returned to a range. The solution applies a third filter to the filtered range which filters all the records having value "H" in the column K and then we count all the visible cells.
This code will turn out to be faster than doing the same thing via loops.
Replace this existing code with this one:
Sub test_calculateval()
Dim rnData, r As Range, ThisYearID, LR, FR, EndR, HomeCount, AwayCount, DrawCount, i As Long, Hometeam As String
ThisYearID = Sheet5.Cells(2, 1).Value - 1
Hometeam = Sheet5.Cells(2, 5)
HomeCount = 0
With Sheet1
Set rnData = Range(Range("A2"), Range("R2").End(xlDown))
With rnData
.AutoFilter
.AutoFilter Field:=1, Criteria1:=">" & ThisYearID - 5
.AutoFilter Field:=5, Criteria1:=Hometeam
.AutoFilter Field:=11, Criteria1:="=H", Operator:=xlAnd
HomeCount = .Columns("K2:K" & (rnData.Rows.Count)).SpecialCells(xlCellTypeVisible).Count-1
End With
End With
MsgBox HomeCount
End Sub
I have the below table that I need to format and remove duplicates but can't work out how to update column G to add all the fixture belonging to that duplicate on one line that remains after the duplicates are removed and in parenthesis I need the qty scanned per fixture ex 10000(1), 10001(5), 10002(1),10003(10).
Sub RemoveDuplicates()
Dim checkLastRow As Long, r1 As Long
Dim DeleteRange As Range
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
CopySheet
With Worksheets("Edited")
checkLastRow = .Range("D" & .Rows.Count).End(xlUp).Row
For r1 = 6 To checkLastRow
If .Cells(r1, 4).Value = Cells(r1 + 1, 4).Value Then
If DeleteRange Is Nothing Then
Set DeleteRange = .Rows(r1)
Else
Set DeleteRange = Union(DeleteRange, .Rows(r1))
End If
End If
Next r1
If Not DeleteRange Is Nothing Then DeleteRange.Delete
End With
Range("A:K").UnMerge
Range("H6:K6").Delete shift:=xlUp
DeleteBlankRows
Range("A1:K4").Merge True
UpdateScreen:
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
Debug.Print Err.Number; Err.Description
MsgBox "Sorry, an error occured." & vbCrLf & Err.Description, vbCritical, "Error!"
Resume UpdateScreen
End Sub
Private Sub CopySheet()
Dim MySheetName As String
MySheetName = "Edited"
Sheets(1).Copy After:=Sheets(1)
ActiveSheet.Name = MySheetName
End Sub
Private Sub DeleteBlankRows()
Dim r As Long
Dim DeleteRange As Range
Dim lastRow As Long
With Worksheets("Edited")
lastRow = .Range("D" & .Rows.Count).End(xlUp).Row
For r = 6 To lastRow
If Application.WorksheetFunction.CountA(Range("A" & r & ":" & "D" & r)) = 0 Then
If DeleteRange Is Nothing Then
Set DeleteRange = Rows(r)
Else
Set DeleteRange = Union(DeleteRange, Rows(r))
End If
End If
Next r
If Not DeleteRange Is Nothing Then DeleteRange.Delete shift:=xlUp
End With
End Sub
Here is one way. It took less than a second to test it on your sample file. It looks big because of the comments :)
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim delRange As Range
Dim lRow As Long, i As Long
Set ws = ActiveSheet
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Delete All rows where Cell A and Cell B are empty
For i = 6 To lRow
If Len(Trim(.Range("A" & i).Value)) = 0 Or Len(Trim(.Range("B" & i).Value)) = 0 Then
If delRange Is Nothing Then
Set delRange = .Rows(i)
Else
Set delRange = Union(delRange, .Rows(i))
End If
End If
Next i
If Not delRange Is Nothing Then delRange.Delete
'~~> Find the new last row
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Insert a new column between G and H
.Columns(8).Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
'~~> Insert a formula =G6 & "(" & I6 & ")" in H6
'~~> Inserting the formula in the entire column in one go
'~~> and converting it to values
.Range("H6:H" & lRow).Formula = "=G6 & ""("" & I6 & "")"""
.Range("H6:H" & lRow).Value = .Range("H6:H" & lRow).Value
'~~> Copy the header from Col G to Col H so that we can delete the
'~~> Column G as it is not required anymore
.Range("H5").Value = .Range("G5").Value
.Columns(7).Delete
'~~> Using a reverse loop to append values from bottom row to the row above
'~~> After appending clear the cell G so that we can later delete the row
For i = lRow To 7 Step -1
If .Range("F" & i).Value = .Range("F" & i - 1).Value Then
.Range("G" & i - 1).Value = .Range("G" & i - 1).Value & "," & .Range("G" & i).Value
.Range("H" & i - 1).Value = .Range("H" & i - 1).Value + .Range("H" & i).Value
.Range("G" & i).ClearContents
End If
Next i
Set delRange = Nothing
'~~> Delete rows where Cell G is empty
For i = 6 To lRow
If Len(Trim(.Range("G" & i).Value)) = 0 Then
If delRange Is Nothing Then
Set delRange = .Rows(i)
Else
Set delRange = Union(delRange, .Rows(i))
End If
End If
Next i
If Not delRange Is Nothing Then delRange.Delete
'~~> Find the new last row
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Calculating the variance
.Range("J6:J" & lRow).Formula = "=H6-I6"
.Range("J6:J" & lRow).Value = .Range("J6:J" & lRow).Value
End With
End Sub
I'm trying to delete an entire row in excel if column B and C are blank for that row. I have this vba code that deletes an entire row if the whole row is blank. How can I only delete the row if B and C have no value?
Thank you
Sub DeleteBlank()
Dim rng
Dim Lastrow As Integer
Set rng = Nothing
Lastrow = Range("A" & Rows.Count).End(xlUp).Row
For Each i In Range("B1:B" & Lastrow)
If Application.CountA(i.EntireRow) = 0 Then
If rng Is Nothing Then
Set rng = i
Else
Set rng = Union(rng, i)
End If
End If
Next i
MsgBox (Lastrow)
If Not rng Is Nothing Then
rng.EntireRow.Delete
End If
End Sub
--Update--
The problem is solved. Thanks to izzymo and sous2817
Here is the current code
Sub DeleteBlank()
Dim i As Integer
Dim Lastrow As Integer
Lastrow = Range("A" & Rows.Count).End(xlUp).Row
MsgBox (Lastrow)
For i = Lastrow To 2 Step -1
If Trim(Range("B" & i).Value) = "" And Trim(Range("C" & i).Value) = "" Then
Range("B" & i).EntireRow.Select
Selection.Delete
End If
Next i
MsgBox "Done"
End Sub
As asked for, here is a way to do it without looping:
Sub NoLoopDelete()
Dim lr As Long
lr = Range("A" & Rows.Count).End(xlUp).Row
With Sheet1.Range("A1:I" & lr)
.AutoFilter
.AutoFilter Field:=2, Criteria1:="="
.AutoFilter Field:=3, Criteria1:="="
.Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete
.AutoFilter
End With
End Sub
The results should be the same, but this way should be faster, especially if you have a lot of rows. Obviously, change the column reference to suit your layout and feel free to fancy it up w/ some error checking,etc.
Try this
Sub DeleteBlank()
Dim i as Integer
Dim Lastrow As Integer
Lastrow = Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To Lastrow
If Trim(Range("B" & i).Value) = "" And Trim(Range("CB" & i).Value) = "" Then
Range("B" & i).EntireRow.Select
Selection.Delete
i = i - 1
End If
Next i
MsgBox "Done"
End Sub
I am getting following error when trying to auto filter in vba:
The object invoked has disconnected from its clients.
So what i am trying to do is auto filter, search for empty spaces and delete the rows. Can anyone please help?
I have tried the standard solutions provided online e.g. option explicit etc but to no avail.
Data:
Code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lngLastRow As Long
Dim lngLastRowD As Long
Application.ScreenUpdating = False
'Concatenate the Row A and B
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
Worksheets(1).Range("D2:D" & lngLastRow).Value = Evaluate("=A2:A" & lngLastRow & "&""""&" & "B2:B" & lngLastRow)
lngLastRowD = Worksheets(1).Cells(Rows.Count, "D").End(xlUp).Row
Set ws = Worksheets(1)
Set Rng = Worksheets(1).Range("A2:A" & lngLastRowD)
With Rng
.AutoFilter field:=1, Criteria1:=""
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
ws.AutoFilterMode = False
Application.ScreenUpdating = True
ThisWorkbook.Sheets(1).Range("A2").Select
End Sub
Since Worksheets() want the name of the sheet, like "Sheet1", use sheets(1).
Why are you creating the variable ws and rng when you only use them once
I ran this and it deleted rows with no data in column A.
Private Sub Worksheet_Change()
Dim lngLastRow As Long
Dim lngLastRowD As Long
Application.ScreenUpdating = False
'Concatenate the Row A and B
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
sheets(1).Range("D2:D" & lngLastRow).Value = Evaluate("=A2:A" & lngLastRow & "&""""&" & "B2:B" & lngLastRow)
lngLastRowD = Worksheets(1).Cells(Rows.Count, "D").End(xlUp).Row
With sheets(1).Range("A2:A" & lngLastRowD)
.AutoFilter field:=1, Criteria1:=""
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
sheets(1).AutoFilterMode = False
Application.ScreenUpdating = True
Sheets(1).Range("A2").Select
End Sub
In the end i restored in approaching the issue from another angle:
Dim i As Integer, counter As Integer
i = 2
For counter = 1 To lngLastRowD
If Worksheets(1).Range("A2:A" & lngLastRowD).Cells(i) = "" And Worksheets(1).Range("D2:D" & lngLastRowD).Cells(i) <> "" Then
Worksheets(1).Range("A2:A" & lngLastRowD).Range("A" & i & ":D" & lngLastRowD).Select
Selection.Delete
GoTo TheEND
Else
i = i + 1
Debug.Print "i is " & i
End If
Next