VBA - Remove rows that have every cell in the range that contain black text - excel

I've been tasked to analyse a workbook where I need to isolate the data based on the colour (red or black) that the text is in relating to the rows.
I essentially need to develop a macro that will remove all the rows that contain data (text) that is 'all black' in the range (column C-J) and leave all the rows that contain at least one cell in the range (column C-J) that contains text that is 'red' (255,0,0).
The completed result should be that every row will contain at least one cell that contains red text between between Column C-J.
The data is set our as follows:
Names:
A1,B1
A2,B2 all the way to
A2000,B2000
Data (text) is set up like the following:
C1 to J1
C2 to J2 all the way to
C2000, J2000
I've found numerous codes that conditionally colour format but I can't seem to develop one that does what I want above.
Any help will be greatly appreciated.

I may as well offer another opinion, just for fun. :-)
Copy and paste the below into a new module, select the area of cells you want to run this over and then execute the macro.
Public Sub RemoveAllRowsWithBlackText()
Dim rngCells As Range, bFoundNonBlack As Boolean, lngRow As Long
Dim lngCol As Long
Set rngCells = Selection
Application.ScreenUpdating = False
With rngCells
For lngRow = .Rows.Count To 1 Step -1
bFoundNonBlack = False
For lngCol = 1 To .Columns.Count
If .Cells(lngRow, lngCol).Font.Color <> 0 And Trim(.Cells(lngRow, lngCol)) <> "" Then
bFoundNonBlack = True
Exit For
End If
Next
If Not bFoundNonBlack Then
.Cells(lngRow, lngCol).EntireRow.Delete xlShiftUp
End If
Next
End With
Application.ScreenUpdating = True
End Sub
... it's not bound to your columns, it will move with the selection you make.

You could try:
Option Explicit
Sub test()
Dim i As Long
With ThisWorkbook.Worksheets("Sheet1")
For i = 2000 To 2 Step -1
If .Range("C" & i).Value = "" And .Range("D" & i).Value = "" And .Range("E" & i).Value = "" And .Range("F" & i).Value = "" _
And .Range("G" & i).Value = "" And .Range("H" & i).Value = "" And .Range("I" & i).Value = "" And .Range("J" & i).Value = "" Then
.Rows(i).Delete
End If
Next i
End With
End Sub

You can use AutoFilter to filter by font color. It does not matter whether the color was derived by manual formatting or conditional formatting.
In your case, you are 'proofing a negative' across many columns. A helper column appears necessary. The code below cycles through columns C:J and marks the 'helper' column every time it encounters filtered rows with a red font.
Sub anyRedFont()
Dim c As Long
With Worksheets("sheet1")
'remove any AutoFilters
If .AutoFilterMode Then .AutoFilterMode = False
'insert a 'helper' column and label it
.Columns("C").Insert
.Cells(1, "C") = "helper"
'filter for red font color
With .Range(Cells(1, "C"), .Cells(.Rows.Count, "K").End(xlUp))
'cycle through columns looking for red font
For c = 2 To 9
'fliter for red font
.AutoFilter Field:=c, Criteria1:=vbRed, _
Operator:=xlFilterFontColor, VisibleDropDown:=False
'put a value into the 'helper' column
On Error Resume Next
With .Resize(.Rows.Count - 1, 1).Offset(1, 0)
Debug.Print .SpecialCells(xlCellTypeVisible).Address(0, 0)
.SpecialCells(xlCellTypeVisible) = 1
End With
On Error GoTo 0
'remove fliter for red font
.AutoFilter Field:=c
Next c
'fliter for non-blank helper column
.AutoFilter Field:=1, Criteria1:=1, VisibleDropDown:=False
End With
'Do your work with the rows containing at least one cell
'with red font here
'remove 'helper' column
'this removes the AutoFilter since the 'helper' column
'is the primary filter column at this point
'.Columns(Application.Match("helper", .Rows(1), 0)).Delete
'remove AutoFilter (manually with Data, Data Tools, Clear)
'If .AutoFilterMode Then .AutoFilterMode = False
End With
End Sub
I've commented out removing the 'helper' column. The 'helper' is the primary filter column so removing it also removes the AutoFilter.

Related

Delete row if cells equal a set of values

I created a macro to in order to generate a daily report. The portion of the macro that finds a value in column AN and deletes the entire row (code edited to delete rows starting from the last used row), works well.
The following example deletes all the rows that do not contain the value "CAT","BAT", or "DOG in column AN.
'False screen updating
Application.ScreenUpdating = False
'deleting all other types other than CAT from "samples" tab (excluding the header row, row 1)
Sheets("sample").Select
Lastrow = Cells(Rows.Count, "AN").End(xlUp).Row
'Deleting rows from bottom up
For i = Lastrow To 2 Step -1
If Range("AN" & i).Value <> "CAT" And _
Range("AN" & i).Value <> "BAT" And _
Range("AN" & i).Value <> "DOG" Then
Rows(i).EntireRow.Delete
End If
Next i
However, would like to create another Sub that deletes all the rows that do contain a specific set of values.
I tried replacing <> with = and ==, however neither worked and no rows were deleted
Below is a sample how to delete rows based on a criteria in column A. Keep in mind that if we delete rows we go backwards to avoid index errors.
Try:
Option Explicit
Sub test()
Dim Lastrow As Long, i As Long
With ThisWorkbook.Worksheets("Sheet1")
Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Where you delete you go backwards
For i = Lastrow To 2 Step -1
If .Range("A" & i).Value = "CAT" Then
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub
Thank you everyone for help resolving this issue. I have found that the root cause of my problem was simply the condition statement at the end of my If/Then line. The "And_" statement was saying "If cell equals CAT and BAT and DOG, then delete row" NOT "If cell equals CAT or BAT or DOG, then delete row". Replacing "And_" with "Or_" has fixed this issue.
'False screen updating
Application.ScreenUpdating = False
'deleting all other types other than CAT from "samples" tab (excluding the header row, row 1)
Sheets("sample").Select
Lastrow = Cells(Rows.Count, "AN").End(xlUp).Row
'Deleting rows from bottom up
For i = Lastrow To 2 Step -1
If Range("AN" & i).Value = "CAT" Or _
Range("AN" & i).Value = "BAT" Or _
Range("AN" & i).Value = "DOG" Or _
Range("AN" & i).Value = "" Then
Rows(i).EntireRow.Delete
End If
Next i
However, I would also like to delete rows if the cells is Blank "". Why would the Sub ignore this line?
Range("AN" & i).Value = "" Then
Thanks!
A site that might be able to help you be the following.
https://www.excelcampus.com/vba/delete-rows-cell-values/
I adjusted the code a little.
Sub Delete_Rows_Based_On_Value()
'Apply a filter to a Range and delete visible rows
'Source: https://www.excelcampus.com/vba/delete-rows-cell-values
Dim ws As Worksheet
'Set reference to the sheet in the workbook.
Set ws = ThisWorkbook.Worksheets("sampel")
ws.Activate 'not required but allows user to view sheet if warning message appears
'Clear any existing filters
On Error Resume Next
ws.ShowAllData
On Error GoTo 0
'1. Apply Filter
ws.Range("AN3:BG1000").AutoFilter Field:=1, Criteria1:="<>CAT"
'2. Delete Rows
Application.DisplayAlerts = False
ws.Range("B1:G1000").SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
'3. Clear Filter
On Error Resume Next
ws.ShowAllData
On Error GoTo 0
End Sub
I would tend to do it this way:
Sub DeleteRows()
Dim i As Integer
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("sample")
i=1
While sht.(i,1) <> "" 'Assuming first column is full of data to the bottom
If sht.Range("AN" & i) = "CAT" Then
sht.Rows(i).EntireRow.Delete
Else
i=i+1
End If
Wend
End Sub

Hiding row if cell equals next visible cell

I am trying to write a macro that hides the row if the cell value equals the next visible cell in that column and loops through the whole column. I have read that SpecialCells(xlCellTypeVisible) only works up to 8192 cells and my spreadsheet has 15,000 rows.
I have tried something like this but want to restrict it to only visible cells
Sub Test()
For i = 7 To 15258
If Range("P" & i).Value = Range("P" & i + 1).Value Then
Rows(i).Hidden = True
End If
Next i
End Sub
I have tried to search for a solution but haven't been able to find one yet.
Thanks!
I'd be surprised if this couldn't be optimized just a little bit, but it will work for what you are needing.
You can follow the comments within the code itself to kind of get a sense of what it's doing, but in a nutshell, you are using a For...Next statement to loop through your visible cells. For each visible cell, you will search for the next visible cell and then check to see if that matches. If it does, you add that cell to a special range that tracks all the rows to hide at the end of the code, then hide it.
Sub Test()
Dim ws As Worksheet, lookupRng As Range, rng As Range, lstRow As Long
Set ws = ThisWorkbook.Worksheets(1)
lstRow = 15258
Set lookupRng = ws.Range("P7:P" & lstRow)
Dim rngToHide As Range, i As Long
For Each rng In lookupRng.SpecialCells(xlCellTypeVisible)
Application.StatusBar = "Checking row " & rng.Row & " for matches."
For i = rng.Row + 1 To lstRow 'Loop through rows after rng
If Not ws.Rows(i).Hidden Then 'Check if row is hidden
If rng.Value = ws.Cells(i, "P") Then 'check if the non-hidden row matches
If rngToHide Is Nothing Then 'Add to special range to hide cells
Set rngToHide = ws.Cells(i, "P")
Else
Set rngToHide = Union(rngToHide, ws.Cells(i, "P"))
End If
End If
Exit For 'Exit the second For statement
End If
Next i
Next rng
Application.StatusBar = "Hiding duplicate rows"
If Not rngToHide Is Nothing Then rngToHide.EntireRow.Hidden = True
Application.StatusBar = False
End Sub

Excel VBA: Maintaining number formatting with digits and letters

I am writing a code where basically I need to follow the sequence in logic. I am going through all the lines
Set rep = Sheets("Details")
For i = 2 To n
If Sheets("Work").Range("A:A").Find(Worksheets("Work_report").Range("E" & i).Value, lookat:=xlWhole) Is Nothing Then
Else:
o = rep.Range("A" & Rows.Count).End(xlUp).Row + 1
rep.Range("A" & o).Value = "FT_EXCEL"
rep.Range("B" & o).Value = Sheets("Start").Range("C5") & "AB" & o - 1
End If
Next i
So this the last line (there are more than 50 in original code) returns me a value of the cell C5 (20170331) & AB & the o minus 1 (because I have started at 2 (1st line header)). So this is giving 20170331AB1, but it should give 20170331AB01 (zero before the 0). This sequence works like a charm after 10, but before ten when I need to add a zero - I got stuck.
Any ideas? Thank you.
Try this:
rep.Range("B" & o).Value = Sheets("Start").Range("C5") & "AB" & Format(o - 1, "00")
you can do it in one shot with exploiting AutoFilter() method's operator xlFilterValues value
Sub main()
Dim rep As Worksheet
Dim criteriaArr As Variant
With Worksheets("Work_report") '<--| reference "Work_report" sheet
criteriaArr = Application.Transpose(.Range("E2", .Cells(.Rows.Count, "E").End(xlUp)).Value) '<--| store its column E cells content from row 2 down to last not empty one
End With
Set rep = Sheets("Details")
With Worksheets("Work") '<--| reference "Work" sheet
With .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)) '<--| reference its column A cells from row 1 (header) down to last not empty one
.AutoFilter Field:=1, Criteria1:=criteriaArr, Operator:=xlFilterValues '<--| filter it with "Work_report" sheet column E content
If Application.WorksheetFunction.Subtotal(103, .Cells) > 1 Then '<--| if any filtered cells other then headers
With .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) '<--| reference filtered cells skipping header
rep.Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(.Rows.Count).Value = "FT_EXCEL" '<--| write 'rep' sheet column A corresponding cells content
With rep.Range("B" & Rows.Count).End(xlUp).Offset(1).Resize(.Rows.Count)
.Formula = "=CONCATENATE(Start!$C$5,""AB"",TEXT(ROW(),""00""))" '<--| '<--| write 'rep' sheet column B corresponding cells content
.Value = .Value
End With
End With
End If
End With
.AutoFilterMode = False
End With
End Sub

Find duplicate macro not working

The following code works on worksheets labeled Walk INs
Sub Find_Duplicatel()
Dim wrkSht As Worksheet 'The worksheet that you're lookin for duplicates in.
Dim rng As Range 'The range containing the duplicates.
Dim Col As Long 'The last column containing data +1
Set wrkSht = ThisWorkbook.Worksheets("Walk INs")
With wrkSht
'Reference to whole data range.
Set rng = .Range("A5:L2003")
'If the sheet is blank an error will be thrown when trying to find the last column.
'This code looks for the last column - you could just set Col to equal the last column number + 1.
On Error Resume Next
Col = 12
Err.Clear
On Error GoTo 0
If Col = 0 Then Col = 0
'Place a COUNTIF formula in the last column.
rng.Offset(, Col).Columns(1).FormulaR1C1 = "=COUNTIF(" & rng.Columns(1).Address(ReferenceStyle:=xlR1C1) & ",RC" & rng.Column & ") & "" duplicates."""
With rng
'Add conditional formatting to first column in range: If the COUNTIF formula is showing >1 then highlight cell.
With .Columns(1)
'This formula is =VALUE(LEFT($M5,FIND(" ",$M5)-1))>1.
'It returns only the number from the duplicate count and checks it is higher than 1.
.FormatConditions.Add Type:=xlExpression, Formula1:= _
"=VALUE(LEFT(" & rng.Offset(, Col).Cells(1).Address(RowAbsolute:=False) & ",FIND("" ""," & _
rng.Offset(, Col).Cells(1).Address(RowAbsolute:=False) & ")-1))>1"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(.FormatConditions.Count).Interior.Color = RGB(0, 100, 255)
End With
'Apply filter to your range.
.AutoFilter
.AutoFilter Field:=12, Criteria1:="Yes"
End With
End With
End Sub`
However when I changed Walk INs to VOC_ASST It hangs up on .AutoFilter I am not certain why. Could you inform me what happened & how to fix it. Other than the sheet titles every thing is identical.
You can add some code it to check if there is an AutoFilter already.
If .AutoFilterMode = False Then
.AutoFilter
.AutoFilter Field:=12, Criteria1:="Yes"
End If
I found the following code on the ENCODEDNA website & after modifying it for my worksheet, it works exactly as I expected.
Sub FIND_DUPLICATE()
`Option Explicit
Dim myDataRng As Range
Dim cell As Range
' WE WILL SET THE RANGE (FIRST COLUMN).
Set myDataRng = Range("A1:A" & Cells(Rows.Count, "B").End(xlUp).Row)
For Each cell In myDataRng
cell.Offset(0, 0).Font.Color = vbBlack ' DEFAULT COLOR.
' LOCATE DUPLICATE VALUE(S) IN THE SPECIFIED RANGE OF DATA.
If Application.Evaluate("COUNTIF(" & myDataRng.Address & "," &
cell.Address & ")") > 1 Then
cell.Offset(0, 0).Font.Color = vbRed ' CHANGE FORE COLOR TO
RED.
End If
Next cell
Set myDataRng = Nothing
ErrHandler:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub`
Thank you to the people that have assisted me.

Trying to delete all Rows until Cell (A,1) has certain value

Having issues in VBA
Trying to delete all rows until value in row 1 = "**GRAD*"
I get Runtime Error 438
Code Below
Public Sub Delete()
Dim i As Long
i = 1 'Start from row 1
Application.ScreenUpdating = False
With ThisWorkbook.Worksheets("Sheet1")
Do Until .Range("A" & i).Value = "**GRAD"
If .Rage("A" & i).Value <> "**GRAD" Then
.Rows(i).EntireRow.Delete
Else: i = i + 1 'Only increment if the row hasn't been deleted to prevent skipping rows
End If
Loop
End With
Application.ScreenUpdating = True
End Sub
Some help would be appreciated, new to VBA.
L.Dutch already gave you the answer to your question
here's an alternative and faster approach
to delete all rows until value in column 1 = "**GRAD*"
Option Explicit
Public Sub Delete()
Dim lastRowToDelete As Long
Dim f As Range
With ThisWorkbook.Worksheets("Sheet0001") '<-- reference your worksheet
With Range("A1", .Cells(.Rows.Count, 1).End(xlUp)) '<-- reference its columns "A" cells from row 1 sown to last not empty one
Set f = .Find(what:="**GRAD", LookIn:=xlValues, lookat:=xlWhole, after:=.Range("A" & .Rows.Count)) '<-- look for the first cell whose value is "**GRAD"
If f Is Nothing Then '<-- if not found then...
lastRowToDelete = .Rows(.Rows.Count).Row '<-- the last row to delete is the last row of the range
Else '<-- otherwise...
lastRowToDelete = f.Row - 1 '<-- the last row to delete is the one preceeding the one with the found cell
End If
End With
If lastRowToDelete > 0 Then .Range("A1:A" & lastRowToDelete).EntireRow.Delete 'delete all rows in a single shot
End With
End Sub
Typo? I read If .Rage("A" & i).Value <> "**GRAD" Then while it should be If .Range("A" & i).Value <> "**GRAD" Then

Resources