I have this code that deletes a row if it has empty cells in columns D to L.
For some reason it is also deleting my title cell which is located at C8.
Anyone knows why? And how to fix it?
Sub RemoveEmptyRows()
Dim ws As Worksheet
For Each ws In Sheets
ws.Activate
Dim n As Long
Dim nlast As Long
Dim rw As Range
Set rw = ActiveWorkbook.ActiveSheet.UsedRange.Rows
nlast = rw.count
For n = nlast To 1 Step -1
If (rw.Cells(n, 4).Value = "" And rw.Cells(n, 5).Value = "" And rw.Cells(n, 6).Value = "" And rw.Cells(n, 7).Value = "" And rw.Cells(n, 8).Value = "" And rw.Cells(n, 9).Value = "" And rw.Cells(n, 10).Value = "" And rw.Cells(n, 11).Value = "") Then
rw.Rows(n).Delete
End If
Next n
Next ws
End Sub
The issue is that you are using the row and column indexes of UsedRange with the assumption that they match the indexes of the Worksheet. This isn't necessarily the case. As you pointed out to #YowE3K in the comments, you have some completely empty columns.
The solution is pretty easy - just use the ws.Cells instead of rw.Cells. I'd also throw everything inside the loop into a With block to make it faster and more readable. You can also short-circuit that long If statement by converting it into a Select Case ladder:
Sub RemoveEmptyRows()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Sheets
With ws
Dim n As Long
Dim nlast As Long
nlast = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For n = nlast To 9 Step -1
Select Case False
Case .Cells(n, 4).Value = vbNullString
Case .Cells(n, 5).Value = vbNullString
Case .Cells(n, 6).Value = vbNullString
Case .Cells(n, 7).Value = vbNullString
Case .Cells(n, 8).Value = vbNullString
Case .Cells(n, 9).Value = vbNullString
Case .Cells(n, 10).Value = vbNullString
Case .Cells(n, 11).Value = vbNullString
Case Else
.Rows(n).Delete
End Select
Next n
End With
Next ws
End Sub
Note that there are also more reliable ways to find the last row of the sheet.
your Title is in C8, then don't delete until Row number 1 :
replace
For n = nlast To 1 Step -1
by
For n = nlast To 9 Step -1
Here is your code a little amended.
Sub RemoveEmptyRows()
Dim ws As Worksheet
Dim n As Long
Dim nlast As Long
Dim rw As Range
For Each ws In Worksheets 'changed. In case there are Chart Sheets.
'deleted ws.activate. AVOID THAT AS PLAGUE
Set rw = ws.UsedRange.Rows
With rw
nlast = .Count
For n = nlast To 2 Step -1 'Note the 2, to skip title row. As was pointed in comments.
If (.Cells(n, 4).Value2 = "" And .Cells(n, 5).Value2 = "" And .Cells(n, 6).Value2 = "" And .Cells(n, 7).Value2 = "" And .Cells(n, 8).Value2 = "" And .Cells(n, 9).Value2 = "" And .Cells(n, 10).Value2 = "" And .Cells(n, 11).Value2 = "") Then
.Rows(n).Delete
End If
Next n
End With 'rw
Next ws
End Sub
You could try this (not tested) code:
Sub RemoveEmptyRows()
Dim ws As Worksheet
Dim nCols As Long
For Each ws In Sheets
With Intersect(.Range("D:K"), .UsedRange)
nCols = .Columns.Count
With .SpecialCells(xlCellTypeBlanks)
For iArea = .Areas.Count To 1 Step -1
If .Areas(iArea).Count = nCols Then .Areas(iArea).EntireRow.Delete
Next
End With
End With
Next ws
End Sub
Related
The code bellow is suppose to do a vlookup in a different worksheet based on some criteria. I declared all the variables and it does its job, but it takes too much time to wait. I believe that this is because of the loop and the two if statements I have, but I cannot see another way of writing two criteria (IF statements). Any other approach will be must appreciated. Thanks!
Please find attached the code below:
Private Sub CommandButton3_Click()
Dim vlookup As Variant
Dim lastRow As Long, lastRow1 As Long
Dim ws As Worksheet, ws1 As Worksheet
Dim j As Long
Set ws = Sheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set ws1 = Sheets("Sheet2")
lastRow1 = ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
For j = 2 To lastRow
If Cells(j, "a") > 1000 And Cells(j, "b") <> "" Then
With ws.Range("f2:f" & lastRow)
.Formula = "=iferror(vlookup(e2, " & ws1.Range("a2:c" & lastRow1).Address(1, 1, external:=True) & ", 3, false), text(,))"
.value = .value
End With
ElseIf Cells(j, "a") > 1000 Then
With ws.Range("f2:f" & lastRow)
.Formula = "=iferror(vlookup(d2, " & ws1.Range("a2:c" & lastRow1).Address(1, 1, external:=True) & ", 3, false), text(,))"
.value = .value
End With
Else
Cells(j, "f") = "No"
End If
Next
End Sub
You are writing and rewriting the same formula(s) into the same cells over and over.
Private Sub CommandButton3_Click()
Dim r As Variant
Dim lastRow As Long, lastRow1 As Long, j As Long
Dim ws As Worksheet, ws1 As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set ws1 = Worksheets("Sheet2")
lastRow1 = ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row
Set rng = ws1.Columns(1)
With ws
For j = 2 To lastRow
If .Cells(j, "a") > 1000 And .Cells(j, "b") <> "" Then
r = Application.Match(.Cells(j, "e").Value2, rng, 0)
If Not IsError(r) Then
.Cells(j, "f") = ws1.Cells(r, "c").Value
else
.Cells(j, "f") = vbnullstring
End If
ElseIf .Cells(j, "a") > 1000 Then
r = Application.Match(.Cells(j, "d").Value2, rng, 0)
If Not IsError(r) Then
.Cells(j, "f") = ws1.Cells(r, "c").Value
else
.Cells(j, "f") = vbnullstring
End If
Else
.Cells(j, "f") = "No"
End If
Next j
End With
End Sub
I want to delete entire row when all 3 numeric values in cells in columns G,H,I are equal. I wrote a vba code and it does not delete nothing. can Someone advise?
Sub remove_dup()
Dim rng As Range
Dim NumRows As Long
Dim i As Long
Set rng = Range("G2", Range("G2").End(xlDown))
NumRows = Range("G2", Range("G2").End(xlDown)).Rows.Count
For i = 2 To NumRows
Cells(i, 7).Select
If Cells(i, 7).Value = Cells(i, 8).Value = Cells(i, 9).Value Then
EntireRow.Delete
Else
Selection.Offset(1, 0).Select
End If
Next i
End Sub
Try this code. When deleting rows, always start from last row and work towards first one. That way you are sure you wont skip any row.
Sub remove_dup()
Dim rng As Range
Dim NumRows As Long
Dim i As Long
NumRows = Range("G2", Range("G2").End(xlDown)).Rows.Count
For i = NumRows + 1 To 2 Step -1
If Cells(i, 7).Value = Cells(i, 8).Value And Cells(i, 7).Value = Cells(i, 9).Value Then
Cells(i, 7).EntireRow.Delete
Else
End If
Next i
End Sub
Remember when you delete rows, all you need to loop in reverse order.
Please give this a try...
Sub remove_dup()
Dim NumRows As Long
Dim i As Long
NumRows = Cells(Rows.Count, "G").End(xlUp).Row
For i = NumRows To 2 Step -1
If Application.CountIf(Range(Cells(i, 7), Cells(i, 9)), Cells(i, 7)) = 3 Then
Rows(i).Delete
End If
Next i
End Sub
You can delete all rows together using UNION. Try this
Sub remove_dup()
Dim ws As Worksheet
Dim lastRow As Long, i As Long
Dim cel As Range, rng As Range
Set ws = ThisWorkbook.Sheets("Sheet4") 'change Sheet3 to your data range
With ws
lastRow = .Cells(.Rows.Count, "G").End(xlUp).Row 'last row with data in Column G
For i = lastRow To 2 Step -1 'loop from bottom to top
If .Range("G" & i).Value = .Range("H" & i).Value And .Range("G" & i).Value = .Range("I" & i).Value Then
If rng Is Nothing Then 'put cell in a range
Set rng = .Range("G" & i)
Else
Set rng = Union(rng, .Range("G" & i))
End If
End If
Next i
End With
rng.EntireRow.Delete 'delete all rows together
End Sub
I am trying to write code to loop through all sheets in a workbook, apart from 1, and add a column which is a concatenation of 3 others. This seems to loop through all the rows for one worksheet, but not the others in the book
Sub addConcats()
Dim sh As Worksheet
Dim rw As Range
Dim RowCount As Integer
'Run through worksheets
Dim x As Long
Sheet1.Select
For x = 2 To ThisWorkbook.Sheets.Count
If Sheets(x).Name <> "VAT Transaction Report" Then Sheets(x).Select
Replace:=False
Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Row - 1 + ActiveSheet.UsedRange.Rows.Count
For y = 2 To LastRow
'Concat
ActiveSheet.Cells(y, 20).Value = ActiveSheet.Cells(y, 7).Value &
ActiveSheet.Cells(y, 9).Value & ActiveSheet.Cells(y, 12).Value
Next y
Next x
End Sub
No need to select each worksheet for this, or run with x and y.
Sub addConcats()
Dim sh As Worksheet
Dim LastRow As Long
For Each sh in ThisWorkbook.Worksheets
If sh.Name <> "VAT Transaction Report" Then
LastRow = sh.Cells(sh.Rows.Count, 1).End(xlUp)
For y = 2 To LastRow
'Concat
sh.Cells(y, 20).Value = sh.Cells(y, 7).Value & sh.Cells(y, 9).Value & sh.Cells(y, 12).Value
Next y
End If
Next
End Sub
Try the code below, for your For loop to take into consideration the Sheets(x) you are trying to update:
Dim LastRow As Long
For x = 2 To ThisWorkbook.Sheets.Count
If Sheets(x).Name <> "VAT Transaction Report" Then
With Sheets(x)
LastRow = .UsedRange.Row - 1 + .UsedRange.Rows.Count
For y = 2 To LastRow
'Concat
.Cells(y, 20).Value = .Cells(y, 7).Value & .Cells(y, 9).Value & .Cells(y, 12).Value
Next y
End With
End If
Next x
The problem is that you select a sheet, but do not use Sheet.Activate. Next you use ActiveSheet. It is better to avoid selecting sheets altogether and just work against a Worksheet object (sh variable)
Try the following:
Sub addConcats()
Dim sh As Worksheet
Dim x As Integer
Dim y As Integer
Dim LastRow As Long
For x = 1 To ThisWorkbook.Sheets.Count
Set sh = Sheets(x)
If sh.Name <> "VAT Transaction Report" Then
LastRow = sh.UsedRange.Rows.Count
For y = 2 To LastRow
'Concat
sh.Cells(y, 20).Value = sh.Cells(y, 7).Value & sh.Cells(y, 9).Value & sh.Cells(y, 12).Value
Next y
End If
Next x
End Sub
So currently I am trying to come up with a if statement. Basically if A3 has any text value I want it to equal awesome. I want to loop this command with the last column in mind.
Sub Criteria
If Range("A2") = "Feedback" And Range("A3") = "**" Then
Range("A1") = "Awesome"
Else
Range("A1") = ""
End If
End sub
(This is the code I came up with can someone help me make it cleaner/faster)
Sub Status()
lastrow = Rows(Rows.Count).End(xlUp).Row
For i = 2 To lastrow
If Cells(i, 1) = "Onsite" And Not IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Feedback"
Else
If Cells(i, 1) = "Phone" And Not IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Feedback"
Else
If Cells(i, 1) = "Phone" And IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Pending Next Step"
Else
If Cells(i, 1) = "Onsite" And IsEmpty(Cells(i, 2)) Then
Cells(i, 3) = "Pending Decision"
End If
End If
End If
End If
Next i
End Sub
Try using Option Explicit also set your worksheet so your not running the code on wrong sheet or to avoid a error
Option Explicit
Public Sub Status()
Dim Sht As Worksheet
Dim rng As Range
Set Sht = ThisWorkbook.Sheets("Sheet1")
For Each rng In Sht.Range("A2", Sht.Range("A9999").End(xlUp))
Debug.Print rng.Address ' print on immed win
DoEvents ' For Debuging
If rng.Value = "Onsite" And rng.Offset(0, 1).Value > 0 Then
rng.Offset(0, 2).Value = "Feedback"
ElseIf rng.Value = "Onsite" And rng.Offset(0, 1).Value = "" Then
rng.Offset(0, 2).Value = "Pending Decision"
End If
If rng.Value = "Phone" And rng.Offset(0, 1).Value > 0 Then
rng.Offset(0, 2).Value = "Feedback"
ElseIf rng.Value = "Phone" And rng.Offset(0, 1).Value = "" Then
rng.Offset(0, 2).Value = "Pending Next Step"
End If
Next
Set Sht = Nothing
Set rng = Nothing
End Sub
Range.Offset Property (Excel)
Syntax: expression.Offset(RowOffset, ColumnOffset)
Returns a Range object that represents a range that?s offset from the specified range.
I would like to change some Book2 value with respect to Book1's value.
Macro code in Book1:
Dim i As Integer
Dim k As Integer
k = Range("Z1")
For i = 1 To k
If Cells(i, 22).Value = "Yes" Then
Windows("Book2").Activate
Cells(i, 11) = ""
Cells(i, 13) = ""
End If
Next i
As commented, you can try re-writing your code like this:
Dim i As Long
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = Workbooks("Book1").Sheets("Sheet1") '~~> change sheet name to suit
Set ws2 = Workbooks("Book2").Sheets("Sheet1")
With ws1
For i = 1 to .Range("Z1").Value
If .Cells(i, 22).Value = "Yes" Then
ws2.Cells(i, 11).Value = ""
ws2.Cells(i, 13).Value = ""
End If
Next
End With