I have a question regarding the below picture, I need to check until the end of the columns.
the check always begins from column "L" but the end change from file to file how needed check.
The below code work very well, still only this small issue, Your help will be appreciated
Sub HighlightInvalidRows()
Application.ScreenUpdating = False
Dim i As Long
Dim c As Long
' Prepare.
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Cumulated BOM")
' Reference the range ('rg').
Dim rg As Range
Set rg = ws.Range("L2", "S" & ws.Cells(ws.Rows.Count, "L").End(xlUp).Row)
' Write the number of columns of the range to a variable ('CellsCount').
Dim CellsCount As Long: CellsCount = rg.Columns.Count
' Each row of the range has this number of columns (cells).
' Remove all range colors.
rg.Interior.Color = xlNone
' Combine the rows ('rrg') to be highlighted
' into the Highlight range ('hrg').
' Declare variables that appear for the first time in the following loop.
Dim hrg As Range
Dim rrg As Range
Dim MatchCount As Long
' Loop through the rows of the range.
For Each rrg In rg.Rows
' Write the number of appearances of the value in the current row
' to a variable ('MatchCount').
MatchCount = Application.CountIf(rrg, "-") Or Application.CountIf(rrg, "")
' Compare the match count with the cells count.
If MatchCount = CellsCount Then ' the numbers are equal
' Combine the current row into the highlight range.
If hrg Is Nothing Then ' the first match
Set hrg = rrg
Else ' all other matches
Set hrg = Union(hrg, rrg)
End If
End If
Next rrg
' Highlight the rows (in one go) and inform.
If hrg Is Nothing Then ' no matches found
MsgBox "No Empty Penetration Found.", vbInformation
Else ' matches found
hrg.Interior.Color = RGB(255, 87, 87)
End If
You define the Range with this statement:
Set rg = ws.Range("L2", "S" & ws.Cells(ws.Rows.Count, "L").End(xlUp).Row)
You fetch the number of rows but hardcode the end column ("S").
There is a question here on SO about how to get the last used row/column/cell in Excel using VBA. Depending on the circumstances, it can get quite tricky, see Find last used cell in Excel VBA.
However, there are two things that you can easily try:
a) Simply use CurrentRegion:
Set rg = ws.Range("L2").CurrentRegion
b) The technique that is used most often to fetch the last row is the logic to "jump" to the last row and then jump back to the last row that is used. Think about as if you jump to the very end of your sheet by pressing Ctrl+Down and then pressing Ctrl+Up. Your code does already exactly that.
Similarly, you can get the last column by pressing Ctrl+Right and then pressing Ctrl+Left.
In Code this could look like that:
Dim lastRow As Long, lastCol As Long
With ws
lastRow = .Cells(.Rows.Count, "L").End(xlUp).Row ' Last row in use in Col L
lastCol = .Cells(2, .Columns.Count).End(xlToLeft).Column ' Last Col in use in row 2
Set rg = .Range(.cells(2, "L"), .cells(lastRow, lastCol))
End With
Reference a Part of a (Table) Range
Note that the code is written for any range and you are having problems only with referencing the range dynamically.
There are several ways to do this but I'll stick with the easiest, most commonly used way, described in more detail in FunThomas' answer.
Replace the following lines...
' Reference the range ('rg').
Dim rg As Range
Set rg = ws.Range("L2", "S" & ws.Cells(ws.Rows.Count, "L").End(xlUp).Row)
... with these:
' In column 'L', determine the last row ('lRow'),
' the row of the bottom-most non-empty cell.
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, "L").End(xlUp).Row
' In row '1' (where the headers are), determine the last column ('lCol'),
' the column of the right-most non-empty cell.
Dim lCol As Long: lCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
' Reference the range ('rg').
Dim rg As Range: Set rg = ws.Range("L2", ws.Cells(lRow, lCol))
Related
Can you help me with this Please, I'm trying to check if from range ("L2") to the end if result = "-" pop up a msgbox & colorize the range.
the conditions is all the cells value in the range horizontally must be = "-"
Example of what I mean:
I try to the below code but it's colorized all the value ("-") in the range
Sheets("Cumulated BOM").Activate
Dim i As Long
Dim c As Long
Dim myRange As Range
Dim myCell As Range
Set myRange = Range("L2", Range("L" & Row.Count).End(xlUp))
For Each myCell In myRange
c = c + 1
If (myCell) = "-" Then
myCell.Interior.Color = RGB(255, 87, 87)
i = i + 1
End If
Next myCell
Highlight Rows With All Their Cells Containing the Same Value
Option Explicit
Sub HighlightInvalidRows()
' Prepare.
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Cumulated BOM")
' Reference the range ('rg').
Dim rg As Range
Set rg = ws.Range("L2", "S" & ws.Cells(ws.Rows.Count, "L").End(xlUp).Row)
' Write the number of columns of the range to a variable ('CellsCount').
Dim CellsCount As Long: CellsCount = rg.Columns.Count
' Each row of the range has this number of columns (cells).
' Remove all range colors.
rg.Interior.Color = xlNone
' Combine the rows ('rrg') to be highlighted
' into the Highlight range ('hrg').
' Declare variables that appear for the first time in the following loop.
Dim hrg As Range
Dim rrg As Range
Dim MatchCount As Long
' Loop through the rows of the range.
For Each rrg In rg.Rows
' Write the number of appearances of the value in the current row
' to a variable ('MatchCount').
MatchCount = Application.CountIf(rrg, "-")
' Compare the match count with the cells count.
If MatchCount = CellsCount Then ' the numbers are equal
' Combine the current row into the highlight range.
If hrg Is Nothing Then ' the first match
Set hrg = rrg
Else ' all other matches
Set hrg = Union(hrg, rrg)
End If
'Else ' the numbers are not equal; do nothing
End If
Next rrg
' Highlight the rows (in one go) and inform.
If hrg Is Nothing Then ' no matches found
MsgBox "No invalid rows found.", vbInformation
Else ' matches found
hrg.Interior.Color = RGB(255, 87, 87)
MsgBox "Invalid rows highlighted.", vbExclamation
End If
End Sub
What is the best way to achieve the requirement from the sample data as per the screenshot attached? I want to merge the RED highlighted font in one row & delete the additional Row. Example - Data in row 4, 6 & 8 can move to the previous column & then 4, 6 & 8 rows should be completely deleted.
Note: there is no consistency in data the inconsistency of data may very between ROWS like B4, C6 & A8.
Delete Entire Rows With Condition
Loops through the rows from the bottom to the top.
If there is at least one blank cell, returns the value of each cell adjacent to the top of each non-blank cell, concatenated with the value of the non-blank cell, in the adjacent cell. Then it combines the first cell of the row into a range.
Deletes the entire rows of the combined range.
Option Explicit
Sub ConcatMissing()
Const SecondDataRowFirstCellAddress As String = "A4"
Const Delimiter As String = ""
Dim ws As Worksheet: Set ws = ActiveSheet
Dim fCell As Range: Set fCell = ws.Range(SecondDataRowFirstCellAddress)
Dim rg As Range
With fCell.CurrentRegion
Set rg = fCell.Resize(.Row + .Rows.Count _
- fCell.Row, .Column + .Columns.Count - fCell.Column)
End With
Dim cCount As Long: cCount = rg.Columns.Count
Dim rrg As Range
Dim rCell As Range
Dim drg As Range
Dim SkipRow As Boolean
Dim r As Long
For r = rg.Rows.Count To 1 Step -1
Set rrg = rg.Rows(r)
If Application.CountBlank(rrg) > 0 Then
For Each rCell In rrg.Cells
If Len(CStr(rCell.Value)) > 0 Then
rCell.Offset(-1).Value = CStr(rCell.Offset(-1).Value) _
& Delimiter & CStr(rCell.Value)
End If
Next rCell
If drg Is Nothing Then
Set drg = rrg.Cells(1)
Else
Set drg = Union(drg, rrg.Cells(1))
End If
End If
Next r
If drg Is Nothing Then Exit Sub
drg.EntireRow.Delete
End Sub
I need some help. I have two columns: A and B. Column A and Column B have the following headers "Status" and "State". A filter has been applied to select "down" from a choice of "up" and "down" in Column A. When Column A is filtered some blank cells are revealed in Column B after some cells in Column B is cleared. The amount of data in the sheet varies and the position of these blanks also vary. I will like to fill down these blank cells in Column B using the values in visible cells only (not from the values in the hidden cells). Can someone help me edit this code?
In the pic above SO will fill down from 50476 to 50492 without erasing the values in the hidden cells.
Sub Filldownvisiblecells ()
Dim ws as worksheet
Dim dl as long
Dim rg as range
ws = Workbooks("Book1.xlsm"). Worksheets("Sheet1")
dl = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'Filter Column A by Down
ws.Range("A1").AutoFilter Field:=1, Criteria1:="Down"
'Clearing States in Column B (This action generates blanks that I will like to filldown from visible cells NOT hidden cells)
ws.Range("B2:B" & dl).SpecialCells(xlCellTypeVisible).Select
For Each rg In Selection.Cells
If rg.Text = "R1" Or rg.Text = "R2" Or rg.Text = "UT" Then
rg.ClearContents
End If
Next rg
'Select Filldown Range in Column B
ws.Range("B2:B" & dl). SpecialCells(xlCellTypeVisible).Select
'Filldown Blanks in Column X
For Each rg In Selection.Cells
If rg.Value = "" Then
rg.FillDown
End If
Next rg
End Sub
Fill Down With Visible Cells' Values (AutoFilter)
Option Explicit
Sub FillDownVisible()
Const wsName As String = "Sheet1"
Const fRow As Long = 1 ' First Row
Const fCol As String = "A" ' Filter Column
Const fCriteria As String = "Down" ' Filter Criteria
Const dCol As String = "B" ' Destination Column
Dim ws As Worksheet
' The Workbook Containing This Code ('ThisWorkbook')
Set ws = ThisWorkbook.Worksheets(wsName)
' An Open Workbook
'Set ws = Workbooks("Book1.xlsm").Wordksheets(wsname)
' Possibly Closed Workbook (Needs the Full File Path)
'Set ws = Workbooks.Open("C:\Test\Book1.xlsm").Worksheets(wsName)
' Clear possible previous ('active') filter.
If ws.AutoFilterMode Then
ws.AutoFilterMode = False
End If
' Create a reference to the Filter Range ('frg').
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, fCol).End(xlUp).Row
Dim frg As Range: Set frg = ws.Cells(fRow, fCol).Resize(lRow - fRow + 1)
' Create a reference to the Destination Data Range (no headers).
Dim ddrg As Range: Set ddrg = frg.EntireRow.Columns(dCol) _
.Resize(frg.Rows.Count - 1).Offset(1)
' Filter Filter Range.
frg.AutoFilter Field:=1, Criteria1:=fCriteria
' Create a reference to the Destination Range ('drg').
Dim drg As Range: Set drg = ddrg.SpecialCells(xlCellTypeVisible)
Dim dCell As Range ' Current Destination Cell
Dim pValue As Variant ' Previous Value
Dim cValue As Variant ' Current Value
' Loop through the cells of the Destination Range.
For Each dCell In drg.Cells
cValue = dCell.Value
Select Case UCase(CStr(cValue))
Case "R1", "R2", "UT", ""
dCell.Value = pValue
Case Else
pValue = cValue
End Select
Next dCell
ws.AutoFilterMode = False
End Sub
I have data in Column A and B in Sheet2 and I have taken some of data from Column A and paste them in column A in Sheet1 and now I want to import data from Sheet2 Column B for matched data of column A in both sheet. I have used below logic to do this but getting error.
For k=2 To 400
Cells(k,2).Value = WorksheetFunction.Index(Sheet2!Range("B2:B1255"), WorksheetFunction.Match(Cells(K, 1).Value, Sheet2!Range("A2:A1255")))
Next k
Index Match Formula in VBA
In the second example, adjust the name of the destination worksheet (Sheet1) appropriately.
The Code
Option Explicit
Sub testFormula()
With Range("B2").Resize(400 - Range("B2").Row + 1)
.Formula = "=IFERROR(INDEX(Sheet2!B$2:B$1255," _
& "MATCH(A2,Sheet2!A$2:A$1255,0)),"""")"
.Value = .Value
End With
End Sub
Sub testVBA()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Define Source Lookup Range.
Dim srg As Range
With wb.Worksheets("Sheet2")
Dim sLast As Long: sLast = .Cells(.Rows.Count, "A").End(xlUp).Row
Set srg = .Range("A2:A" & sLast) ' i.e. '.Range("A2:A1255")'
' Or just:
'Set srg = .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
End With
' Define Destination Lookup Range.
Dim drg As Range
With wb.Worksheets("Sheet1")
Dim dLast As Long: dLast = .Cells(.Rows.Count, "A").End(xlUp).Row
Set drg = .Range("A2:A" & dLast) ' i.e. '.Range("A2:A400")'
' Or just:
'Set drg = .Range("A2:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
End With
' Loop through cells of Destination Lookup Range...
Dim dCell As Range
Dim cIndex As Variant ' Can be an error value, hence 'Variant'.
' Loop through cells of Destination Lookup Range.
For Each dCell In drg.Cells
' Attempt to find a match (the first occurrence) of the value
' in the current cell of Destination Lookup Range,
' in cells of Source Lookup Range.
cIndex = Application.Match(dCell.Value, srg, 0)
' If a match is found...
If IsNumeric(cIndex) Then
' Write the value from the cell associated (in the same row)
' to the matched cell (i.e. Source Column 'B'), to the cell
' associated (in the same row) to the current cell
' (Destination Column 'B').
dCell.Offset(, 1).Value = srg.Cells(cIndex).Offset(, 1).Value
' IF no match found (error value)...
Else
dCell.Offset(, 1).Value = ""
End If
Next dCell
End Sub
I was recently assisted by a member of this community in addressing how I should build out a macro for my project. The following macro works precisely as I would like it to. However, there is a manual dependency that I am trying to correct.
The source range is predefined as specific cell references (e.g. A10, B10, C10, F10...) After I run this macro, I would like the source range to move down to the next row so that the next time the macro is called, it copies A11, B11, C11, F11...
Please let me know if this is possible. The following is the VBA code I've been using:
Public Sub Update_Project_1()
' Set a reference to the source sheet
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("High Level Tracker")
' Set a reference to the target sheet
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Worksheets("Project 1 Detailed Tracker")
' Set a reference to the source range
Dim sourceRange As Range
Set sourceRange = sourceSheet.Range("A10,B10,C10,F10,H10")
' Get last row in target sheet
Dim lastRow As Long
lastRow = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row
' Loop through each cell in source range
Dim sourceCell As Range
For Each sourceCell In sourceRange.Cells
' Output values from source range into next empty row in target
Dim columnCounter As Long
targetSheet.Range("A" & lastRow + 1).Offset(, columnCounter).Value = sourceCell.Value
columnCounter = columnCounter + 1
Next sourceCell
End Sub
Any help would be kindly appreciated, thanks!
You can find the last empty row in the source sheet and then copy the values to the target sheet
Public Sub Update_Project_1()
' Set a reference to the source sheet
Dim sourceSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("High Level Tracker")
' Set a reference to the target sheet
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Worksheets("Project 1 Detailed Tracker")
' Get last row in source sheet
Dim lastRowSource As Long
lastRowSource = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row
' Define the source range address
Dim sourceRangeAddress As String
sourceRangeAddress = "A<r>,B<r>,C<r>,F<r>,H<r>"
' Replace next row in source rane
sourceRangeAddress = Replace(sourceRangeAddress, "<r>", lastRowSource)
' Set a reference to the source range
Dim sourceRange As Range
Set sourceRange = sourceSheet.Range(sourceRangeAddress)
' Get last row in target sheet
Dim lastRowTarget As Long
lastRowTarget = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row
' Loop through each cell in source range
Dim sourceCell As Range
For Each sourceCell In sourceRange.Cells
' Output values from source range into next empty row in target
Dim columnCounter As Long
targetSheet.Range("A" & lastRowTarget + 1).Offset(, columnCounter).Value = sourceCell.Value
columnCounter = columnCounter + 1
Next sourceCell
End Sub
Not the cleanest one, but it may help.
At start of your code, just add:
Dim ThisRow As Long
ThisRow = InputBox("What row?", , 10)
This will ask user in every execution of macro a row number (default value =10)
Then replace line
Set sourceRange = sourceSheet.Range("A10,B10,C10,F10,H10")
with
Set sourceRange = sourceSheet.Range("A" & ThisRow & ",B" & ThisRow & ",C" & ThisRow & ",F" & ThisRow & ",H" & ThisRow)
This way, every execution will allow you to choose what the target row, without editing code manually.
Your current cell is called ActiveCell. In order to go to another cell, you might use the Offset() function.
So, both combined give following line of source code:
ActiveCell.Offset(1,0).Activate
This means: take the current active cell, go one row further but no columns (1,0), and activate that cell.