Code wont loop through sheets as well as rows - vba

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

Related

Loop and IF statement takes too much time

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

Excel VBA Remove Triple Duplicate in One Row Loop

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

VBA code deleting incorrect rows

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

Color non-adjacent cells that match criteria

I use the below code to color the cells in column K and Z that match the criteria; but it colors all cells between K and Z. To fix, I use the last line of code to remove the color in columns L thru Y. Is there a way to modify the line of code that starts with "Range" to only color cells K and Z that match the criteria?
Sub ColrCls()
Dim ws As Worksheet
Dim lRow As Long, i As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("K" & .Rows.Count).End(xlUp).Row
For i = 2 To lRow
If .Cells(i, 11).Value = "Non Sen" And .Cells(i, 26).Value = "N/A" Then
Range(.Cells(i, 11), .Cells(i, 26)).Interior.ColorIndex = 6
End If
Next i
Columns("L:Y").Interior.ColorIndex = xlNone
End With
End Sub
You are specifying the Range.Parent property in your With ... End With statement but ignoring it when it is most important¹.
Sub ColrCls()
Dim ws As Worksheet
Dim lRow As Long, i As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("K" & .Rows.Count).End(xlUp).Row
For i = 2 To lRow
If .Cells(i, 11).Value = "Non Sen" And .Cells(i, 26).Value = "N/A" Then
.Range("K" & i & ", Z" & i).Interior.ColorIndex = 6
Else
.Range("K" & i & ", Z" & i).Interior.Pattern = xlNone
End If
Next i
End With
End Sub
A Range object to Union discontiguous cells could be one of the following.
.Range("K5, Z5")
Union(.Cells(5, "K"), .Cells(5, "Z"))
In the example above, I've concatenated together a string like the first of these two examples.
¹ See Is the . in .Range necessary when defined by .Cells? for an earnest discussion on this subject.
You could replace
Range(.Cells(i, 11), .Cells(i, 26)).Interior.ColorIndex = 6
with
.Cells(i, 11).Interior.ColorIndex = 6
.Cells(i, 26).Interior.ColorIndex = 6

VBA Dynamic Filtering and Copy Paste into new worksheet

I am trying to write a vba script that will filter on two columns, column A and column D. Preferably, I want to create a button that will execute once I have chosen the filter criteria. Sample of input data below.
Sub Compiler()
Dim i
Dim LastRow As Integer
LastRow = Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
Sheets("Sheet4").Range("A2:J6768").ClearContents
For i = 2 To LastRow
If Sheets("Sheet1").Cells(i, "A").Values = Sheets("Sheet3").Cells(3, "B").Values And Sheets("Sheet1").Cells(i, "D").Values = Sheets("Sheet3").Cells(3, "D").Values Then
Sheets("Sheet1").Cells(i, "A" & "D").EntireRow.Copy Destination:=Sheets("Sheet4").Range("A" + Rows.Count).End(xlUp)
End If
Next i
End Sub
Sample Data to run vba script
I have included my previous answer's changes into the full code block that is now provided below.
Sub Compiler()
Dim i
Dim LastRow, Pasterow As Integer
Dim sht As Worksheet
Set sht = ThisWorkbook.Sheets("Sheet4")
LastRow = Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
Sheets("Sheet4").Range("A2:J6768").ClearContents
For i = 2 To LastRow
If Sheets("Sheet1").Range("A" & i).Value = Sheets("Sheet3").Range("B3").Value And Sheets("Sheet1").Range("D" & i).Value = Sheets("Sheet3").Range("D3").Value Then
Pasterow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row + 1
Sheets("Sheet1").Rows(i).EntireRow.Copy Destination:=Sheets("Sheet4").Range("A" & Pasterow)
End If
Next i
Sheets("sheet4").Rows(1).Delete
End Sub
Sheets("Sheet1").Cells(i, "A").Values
Sheets("Sheet3").Cells(3, "B").Values
etc
You keep using values. Don't you mean value?
This answered the question I was asking, I tried to work with Dan's answer but didn't get very far.
Private Sub CommandButton1_Click()
FinalRow = Sheets("Sheet1").Cells(rows.Count, 1).End(xlUp).Row
Sheets("Sheet4").Range(Sheets("Sheet4").Cells(1, "A"), Sheets("Sheet4").Cells(FinalRow, "K")).ClearContents
If Sheets("Sheet4").Cells(1, "A").Value = "" Then
Sheets("Sheet1").Range("A1:K1").Copy
Sheets("Sheet4").Range(Sheets("Sheet4").Cells(1, "A"), Sheets("Sheet4").Cells(1, "K")).PasteSpecial (xlPasteValues)
End If
For x = 2 To FinalRow
ThisValue = Sheets("Sheet1").Cells(x, "A").Value
ThatValue = Sheets("Sheet1").Cells(x, "D").Value
If ThisValue = Sheets("Sheet3").Cells(3, "B").Value And ThatValue = Sheets("Sheet3").Cells(3, "D").Value Then
Sheets("Sheet1").Range(Sheets("Sheet1").Cells(x, 1), Sheets("Sheet1").Cells(x, 11)).Copy
Sheets("Sheet4").Select
NextRow = Sheets("Sheet4").Cells(rows.Count, 1).End(xlUp).Row + 1
With Sheets("Sheet4").Range(Sheets("Sheet4").Cells(NextRow, 1), Sheets("Sheet4").Cells(NextRow, 11))
.PasteSpecial (xlPasteFormats)
.PasteSpecial (xlPasteValues)
End With
End If
Next x
Worksheets("Sheet4").Cells.EntireColumn.AutoFit
End Sub