vba - Shading entire row based on date - vba

Each week I get new data and I m filtering for for "n/a" column from another sheet and grabbing the rest of the columns and adding them to my existing sheet of the same workbook and I need to color the rows that have dates smaller than tomorrow's date, so today or prior. New data range varies each week and I only want to color new data. I am checking dates using column D and there are also dates in column C so I don't know if that will complicate the task.
I know this can be achieved using conditional formatting, but I want to use vba codes to automate the process.
My codes won't work since it can't determine where my new data starts and only colors column D not the whole row if it fits the criteria. Please see my codes and my desire result.
Sub paste_value()
Dim ws1, ws2 As Worksheet
Dim lr1, lr2 As Long
Dim rCell As Range
'filter
Set ws1 = Worksheets("All Renewals_V2")
Set ws2 = Worksheets("Renewal policies")
lr1 = ws1.Cells(Rows.Count, "B").End(xlUp).Row
lr2 = ws2.Cells(Rows.Count, "A").End(xlUp).Row
'copy range from column B to column R
With ws1.Range("B2", "R" & lr1)
.AutoFilter Field:=1, Criteria1:="#N/A"
'paste result from column A
.Copy Destination:=Cells(lr2, "A")
End With
For Each rCell In .Range("D5", .Cells(.Rows.Count, 4).End(xlUp)).Cells
If rCell.Value <= Date + 1 Then
rCell.Interior.color = vbYellow
End If
Next rCell
End Sub

If I am understanding your question correctly, I think the following modifications to your code will enable it to work:
Sub paste_value()
'Dim ws1, ws2 As Worksheet
'Dim lr1, lr2 As Long
'existing code declared ws1 and lr1 as Variants
Dim ws1 As Worksheet, ws2 As Worksheet
Dim lr1 As Long, lr2 As Long
Dim rCell As Range
'filter
Set ws1 = Worksheets("All Renewals_V2")
Set ws2 = Worksheets("Renewal policies")
'lr1 = ws1.Cells(Rows.Count, "B").End(xlUp).Row
'Should qualify which sheet "Rows" refers to
lr1 = ws1.Cells(ws1.Rows.Count, "B").End(xlUp).Row
'lr2 = ws2.Cells(Rows.Count, "A").End(xlUp).Row
'Need to add 1 or else the first row of this week will replace the last
'row of last week
lr2 = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row + 1
'copy range from column B to column R
With ws1.Range("B2", "R" & lr1)
.AutoFilter Field:=1, Criteria1:="#N/A"
'paste result from column A
'.Copy Destination:=Cells(lr2, "A")
'Should specify that ws2 is the sheet to which "Cells" refers
.Copy Destination:=ws2.Cells(lr2, "A")
End With
'I am guessing that the following statement is missing
With ws2
'For Each rCell In .Range("D5", .Cells(.Rows.Count, 4).End(xlUp)).Cells
'Need to start the colouring from the first row pasted in
For Each rCell In .Range("D" & lr2, .Cells(.Rows.Count, 4).End(xlUp)).Cells
If rCell.Value <= Date + 1 Then
'rCell.Interior.color = vbYellow
'Change as per Scott Holtzman's comment
rCell.Offset(, -3).Resize(1, 5).Interior.Color = vbYellow
'Or an alternate version would be
' rCell.EntireRow.Columns("A:E").Interior.Color = vbYellow
'Use whichever version makes the most sense to you
End If
Next rCell
End With
End Sub

Related

How to dynamically select a range VBA

My question is very similar to the following:
Excel VBA code to select non empty cells
However, I have some empty cells in between. In particular, I'm trying to define a range where the first row needs to be excluded, since it's a header. I also have to exclude the empty cells that follow. I was trying something like
Dim wb as workbook, ws as worksheet
Dim myrange as range
'Defined reference wb and ws
myrange=ws.range("B2",range("B2"),end(xldown))
But this only works if there are not empty cells in between. So, is there a fast and simple way to dynamically select a range that includes non-empty cells, excepted the header?
Try this
'Defined reference wb and ws
Set myrange = ws.range("B2", ws.Range("B" & Rows.Count).End(xlUp))
Don't forget to use the Set keyword
Try the next way, please:
Sub testDefineRange()
Dim ws As Worksheet, lastRow As Long, myrange As Range
Set ws = ActiveSheet 'use here what you need
lastRow = ws.Range("B" & ws.rows.count).End(xlUp).row
'Defined reference ws
Set myrange = ws.Range("B2:B" & lastRow)
myrange.Select
End Sub
I have found this link to be very useful on MANY occasions.
https://www.thespreadsheetguru.com/blog/2014/7/7/5-different-ways-to-find-the-last-row-or-last-column-using-vba
Ways To Find The Last Row
Sub FindingLastRow()
'PURPOSE: Different ways to find the last row number of a range
'SOURCE: www.TheSpreadsheetGuru.com
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ActiveSheet
'Using Find Function (Provided by Bob Ulmas)
LastRow = sht.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
'Using SpecialCells Function
LastRow = sht.Cells.SpecialCells(xlCellTypeLastCell).Row
'Ctrl + Shift + End
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
'Using UsedRange
sht.UsedRange 'Refresh UsedRange
LastRow = sht.UsedRange.Rows(sht.UsedRange.Rows.Count).Row
'Using Table Range
LastRow = sht.ListObjects("Table1").Range.Rows.Count
'Using Named Range
LastRow = sht.Range("MyNamedRange").Rows.Count
'Ctrl + Shift + Down (Range should be first cell in data set)
LastRow = sht.Range("A1").CurrentRegion.Rows.Count
End Sub
Ways To Find The Last Column
Sub FindingLastColumn()
'PURPOSE: Different ways to find the last column number of a range
'SOURCE: www.TheSpreadsheetGuru.com
Dim sht As Worksheet
Dim LastColumn As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
'Ctrl + Shift + End
LastColumn = sht.Cells(7, sht.Columns.Count).End(xlToLeft).Column
'Using UsedRange
sht.UsedRange 'Refresh UsedRange
LastColumn = sht.UsedRange.Columns(sht.UsedRange.Columns.Count).Column
'Using Table Range
LastColumn = sht.ListObjects("Table1").Range.Columns.Count
'Using Named Range
LastColumn = sht.Range("MyNamedRange").Columns.Count
'Ctrl + Shift + Right (Range should be first cell in data set)
LastColumn = sht.Range("A1").CurrentRegion.Columns.Count
End Sub
If it suits your case, I like to use CurrentRegion with Intersect to eliminate the title row.
with ws.range("b2")
set myRange = intersect(.currentregion, .currentregion.offset(1,0))
end with
debug.print myRange.address

Copy varying range from multiple sheets and paste from same row

I am working currently with one workbook and want to implement a preparatory work, copy/pasting all the relevant range from my workbook contained in separate worksheets (3 worksheets at most).
I have the below code to loop through the worksheets, unfortunately I am unable to write the paste-command so as to paste these ranges from the same row successively. I want Transpose:= True. I.E Rgn from sheet1 starting from B2, after last filled cell on the right starts Rgn from Sheet2, after last filled cell starts Rgn from Sheet3 (provided Rgn exists for Sheet3).
Currently, my code overwrites what was copied from previous sheet.
I found a potential reference here (VBA Copy Paste Values From Separate Ranges And Paste On Same Sheet, Same Row Offset Columns (Repeat For Multiple Sheets)) but I am not sure how to use Address nor how the Offset is set in the solution.
' Insert temporary tab
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Sheets(1).Range("D16:D18").Copy
Case 2
lastrow = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(2).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(2).Range("M9", Sheets(2).Cells(lastrow, lastcol))
Rng.Copy
Case 3
'Check if Range (first col for answers) is not empty
If Worksheetunction.CountA(Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(3).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(3).Range("L9", Sheets(3).Cells(lastrow, lastcol))
Rng.Copy
End If
End Select
wb.Sheets("Prep").UsedRange.Offset(1,1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing
Can you try this? UsedRange can be unpredictable. You can also have problems if you don't have anything in the first cell of Rng, in which case this code will need adjusting.
I would also prefer to use the sheeet name rather than index.
Sub x()
Dim sh As Worksheet, wb As Workbook, Rng As Range
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Set Rng = sh.Range("D16:D18")
Case 2
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("M9", sh.Cells(lastrow, lastcol))
Case 3
'Check if Range (first col for answers) is not empty
If WorksheetFunction.CountA(sh.Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("L9", sh.Cells(lastrow, lastcol))
End If
End Select
Rng.Copy
wb.Sheets("Prep").Cells(2, Columns.Count).End(xlToLeft).Offset(, 1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing
End Sub

Comparing two columns, finding mismatches and pasting entire row in a new worksheet using VBA

I'm trying to write a macro in VBA that will compare values in two different columns, find the mismatches and then copy and paste the entire row of the mismatched value to a new worksheet. My code is below.
My code works doing this with the individual values (which I commented out below) but when I try to copy and paste the entire row, that's when things don't work.
Public Sub CompareNumber(sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet)
Dim lr1 As Long, lr2 As Long, rng1 As Range, rng2 As Range, c As Range
lr1 = sh1.Cells(Rows.Count, 2).End(xlUp).Row 'Get the last row with data for both list sheets
lr2 = sh2.Cells(Rows.Count, 2).End(xlUp).Row
Set rng1 = sh1.Range("B2:B" & lr1) 'Establish the ranges on both sheets
Set rng2 = sh2.Range("B2:B" & lr2)
For Each c In rng1 'Run a loop for each list, ID mismatches and paste to sheet 3.
If WorksheetFunction.CountIf(rng2, c.Value) = 0 Then
c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)
'sh3.Cells(Rows.Count, 2).End(xlUp)(2) = c.Value
End If
Next
For Each c In rng2
If Application.CountIf(rng1, c.Value) = 0 Then
c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)
'sh3.Cells(Rows.Count, 2).End(xlUp)(2) = c.Value
End If
Next
End Sub
Any help is greatly appreciated!
In the source data is ColumnA always populated? If not that will cause problems when pasting rows to sh3 - an empty cell in colA will cause the next-pasted row to overwrite the previous one.
Something like this is a bit safer (plus a little refactoring to abstract out the repeated loop):
Public Sub CompareNumber(sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet)
Dim rng1 As Range, rng2 As Range, rngDest As Range
'Establish the ranges on both sheets
Set rng1 = sh1.Range(sh1.Range("B2"), sh1.Cells(Rows.Count, 2).End(xlUp))
Set rng2 = sh2.Range(sh2.Range("B2"), sh2.Cells(Rows.Count, 2).End(xlUp))
Set rngDest = sh3.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
CopyMismatches rng1, rng2, rngDest
CopyMismatches rng2, rng1, rngDest
End Sub
Private Sub CopyMismatches(rngSrc As Range, rngMatch As Range, rngDest As Range)
Dim c As Range
For Each c In rngSrc
If Application.CountIf(rngMatch, c.Value) = 0 Then
c.EntireRow.Copy rngDest
Set rngDest = rngDest.Offset(1, 0) '<< safer if could be empty colA values
End If
Next
End Sub
Try
"sh1.rows(c1.row).EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)"
instead of
"c.EntireRow.Copy sh3.Range("A" & Rows.Count).EntireRow.End(xlUp)(2)"
This may work

How to start selecting at row 2, rather than all rows?

How can I modify the following to limit the selection to only start at row 2? Currently it selects every row.
Set myRng = .Range("D2", .Cells(.Rows.Count, "D").End(xlUp))
To make it work, you will have to ensure that there is data in cell D2. See this example.
Sub Sample()
Dim myRng As Range
Dim ws As Worksheet
Dim Lrow As Long
'~~> Change this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Get last row which has data in Col D
Lrow = .Range("D" & .Rows.Count).End(xlUp).row
If Not Lrow < 2 Then
Set myRng = .Range("D2:D" & Lrow)
MsgBox myRng.Address
Else
MsgBox "There is no data in cell D2"
End If
End With
End Sub

VBA macro code for listing names

I have an Excel sheet with names as one column and their working hours as values in next column.
I want to copy names with values greater than 40 to new sheet without any blanks in columns. The new sheet should have both names and the working hours; any text in the values column should be ignored.
Sub CopyCells()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim j As Long, i As Long, lastrow1 As Long
Set sh1 = Worksheets("Sheet1")
Set sh2 = Worksheets("Sheet2")
lastrow1 = sh1.Cells(Rows.Count, "F").End(xlUp).Row
For i = 1 To lastrow1
If sh1.Cells(i, "F").Value > 20 Then
sh2.Range("A" & i).Value = sh1.Cells(i, "F").Value
End If
Next i
End Sub
I would recommend using AutoFilter to copy and paste as it is faster than looping. See the example below.
My Assumptions
Original Data is in Sheet 1 as shown the snapshot below
You want the output in Sheet 2 as shown the snapshot below
CODE
I have commented the code so that you will not have a problem understanding it.
Option Explicit
Sub Sample()
Dim wsI As Worksheet, wsO As Worksheet
Dim lRow As Long
'~~> Set the input sheet
Set wsI = Sheets("Sheet1"): Set wsO = Sheets("Sheet2")
'~~> Clear Sheet 2 for output
wsO.Cells.ClearContents
With wsI
'~~> Remove any existing filter
.AutoFilterMode = False
'~~> Find last row in Sheet1
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Filter Col B for values > 40
With .Range("A1:B" & lRow)
.AutoFilter Field:=2, Criteria1:=">40"
'~~> Copy the filtered range to Sheet2
.SpecialCells(xlCellTypeVisible).Copy wsO.Range("A1")
End With
'~~> Remove any existing filter
.AutoFilterMode = False
End With
'~~> Inform user
MsgBox "Done"
End Sub
SNAPSHOT
Try rhis
Sub CopyCells()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim j As Long, i As Long, lastrow1 As Long
Set sh1 = Worksheets("Sheet1")
Set sh2 = Worksheets("Sheet2")
lastrow1 = sh1.Cells(Rows.Count, "F").End(xlUp).Row
j = 1
For i = 1 To lastrow1
If Val(sh1.Cells(i, "F").Value) > 20 Then
sh2.Range("A" & j).Value = sh1.Cells(i, "F").Value
j = j + 1
End If
Next i
End Sub