Excel VBA | Include Blank Cells Below an Already Selected Cell In a Range - excel

I have a script partially written. I'm stuck on how to include all blank cells below a selected cell and store this as a range. My script selects the top cell in the range I want - Cell N39 - and I want to select each of the blank cells below it. That is, I want to select N39 thru N42 and name it as a range.
I know there are other ways to capture this range (ie - all of the "BlankNonUSD" descriptions I add on the far right could help me). But the only way I can grab only the data I need and not accidentally include data I don't need is to select this "N39" cell and every empty cell below it. I want to ensure this script can run for all sheets it will be used for and this is the way to do it.
I have my script below and a link to the picture of the sheet I referenced. Any help would be highly appreciated!
Script:
'Convert "BlankNonUSD" and move values to "Amount USD" (Column N)
For i = 1 To IDLastRow
If Cells(i, 16) = "BlankNonUSD" And Cells(i, 14) <> "" Then
Range("N" & i).Select
'This is where I also want to select all cells below
'Dim r As Range
'Set r = Selection
'Dim x As Integer
'Dim y As Integer
'x = r.Rows
'y = r.Rows.Count + x - 1
'Dim USDTotal As Integer
'USDTotal = Range("N" & i).Value
'Dim nonUSDTotal As Integer
'nonUSDTotal = ActiveSheet.Sum(r)
'For Z = x To y
'Cells(i, 17) = Round(((Cells(i, 14).Value / nonUSDTotal) * USDTotal), 2)
'Next
End If
Next
Picture of Sheet

Reference Cell and Blanks Adjacent to the Bottom
In your code you would call the function in the following way:
RefCellBottomBlanks(Range("N" & i)).Select
The Function
Function RefCellBottomBlanks( _
ByVal FirstCell As Range) _
As Range
With FirstCell.Cells(1)
Dim lCell As Range: Set lCell = _
.Resize(.Worksheet.Rows.Count - .Row + 1).Find("*", , xlValues)
If lCell Is Nothing Then Exit Function ' no data in column
If lCell.Row <= .Row + 1 Then ' no blanks adjacent to the bottom
Set RefCellBottomBlanks = .Cells
Else
Set RefCellBottomBlanks = .Resize(lCell.Row - .Row)
End If
End With
End Function
A Test Procedure
Sub RefCellBottomBlanksTEST()
Const fCellAddress As String = "N39"
Dim ws As Worksheet: Set ws = ActiveSheet
Dim fCell As Range: Set fCell = ws.Range(fCellAddress)
Dim rg As Range: Set rg = RefCellBottomBlanks(fCell)
Debug.Print rg.Address
End Sub

Related

Excel VBA - For Loop IS taking far far too long to execute

First question ever here, I am the newbiest newbie..
So.. what I am trying to get is:
to find if in sheet1 and sheet2 there are cells with the same value on column E from sheet1 and column F from sheet2. if there are, then copy the value from sheet2 column A row x to sheet2 column P row y.
rows x and y are where the identical values are on each sheet.
this is my code:
Sub ccopiazanrfact()
Dim camion As Worksheet
Dim facturi As Worksheet
Set camion = ThisWorkbook.Sheets("B816RUS")
Set facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
Dim nrcomanda As String
Dim nrfactura As String
For a = 2 To facturi.Range("F" & Rows.Count).End(xlUp).Row
nrcomanda = facturi.Range("F" & a).Value
For b = 4 To camion.Range("E" & Rows.Count).End(xlUp).Row
If camion.Range("E" & b).Value = facturi.Range("F" & a).Value Then
camion.Range("P" & b) = facturi.Range("A" & a).Value
Exit For
End If
Next b
Next a
End Sub
I would recommend using arrays to achieve what you want. Nested looping over ranges can make it very slow. Is this what you are trying? (UNTESTED). As I have not tested it, I would recommend making a backup of your data before you test this code.
I have commented the code. But if you still have a question or find an error/bug in the below code then simply ask.
Option Explicit
Sub ccopiazanrfact()
Dim Camion As Worksheet
Dim Facturi As Worksheet
Set Camion = ThisWorkbook.Sheets("B816RUS")
Set Facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
'~~> Declare 2 arrays
Dim ArCamion As Variant
Dim ArFacturi As Variant
Dim LRow As Long
'~~> Find last row in Col E of Sheets("B816RUS")
LRow = Camion.Range("E" & Camion.Rows.Count).End(xlUp).Row
'~~> Store Values from E4:P last row in the array. We have taken E:P
'~~> because we are replacing the value in P if match found
ArCamion = Camion.Range("E4:P" & LRow).Value
'~~> Find last row in Col E of Sheets("EVIDENTA FACTURI")
LRow = ArFacturi.Range("F" & ArFacturi.Rows.Count).End(xlUp).Row
'~~> Store Values from A2:F last row in the array. We have taken A:F
'~~> because we are replacing the value in P with A
ArFacturi = Facturi.Range("A2:F" & LRow).Value
Dim i As Long, j As Long
For i = 2 To UBound(ArFacturi)
For j = 4 To UBound(ArCamion)
'~~> Checking if camion.Range("E" & j) = facturi.Range("F" & i)
If ArCamion(j, 1) = ArFacturi(i, 6) Then
'~~> Replacing camion.Range("P" & j) with facturi.Range("A" & i)
ArCamion(j, 12) = ArFacturi(i, 1)
Exit For
End If
Next j
Next i
'~~> Write the array back to the worksheet in one go
Camion.Range("E4:P" & LRow).Resize(UBound(ArCamion), 12).Value = ArCamion
End Sub
in the end, I came up with this and works instantly, get’s all the data filled within a blink of an eye. When I tried it first time I thought i forgot to clear the data before running the code:
Sub FindMatchingValues()
'Declare variables for the worksheets
Dim ws1 As Worksheet
Dim ws2 As Worksheet
'Set the variables to refer to the worksheets
Set ws1 = Worksheets("B816RUS")
Set ws2 = Worksheets("EVIDENTA FACTURI")
'Declare variables for the ranges to compare
Dim rng1 As Range
Dim rng2 As Range
'Set the ranges to the columns to compare
Set rng1 = ws1.Range("E1", ws1.Range("E" & Rows.Count).End(xlUp))
Set rng2 = ws2.Range("F1", ws2.Range("F" & Rows.Count).End(xlUp))
'Loop through each cell in the first range
For Each cell1 In rng1
'Use the Match function to find the matching value in the second range
Dim match As Variant
match = Application.match(cell1.Value, rng2, 0)
'If a match was found, copy the value from column A in the second worksheet to column P in the first worksheet
If Not IsError(match) Then
ws1.Range("P" & cell1.Row).Value = ws2.Range("A" & match).Value
End If
Next cell1
End Sub
Please, test the next code. It should be very fast, using arrays and Find function:
Sub ccopiazaNrfact()
Dim camion As Worksheet, facturi As Worksheet, cellMatch As Range, rngE As Range
Set camion = ThisWorkbook.Sheets("B816RUS")
Set facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
Set rngE = camion.Range("E4:E" & camion.Range("E" & camion.rows.count).End(xlUp).row)
Dim a As Long, arrFact, arrP, nrComanda As String
arrP = camion.Range("P1:P" & camion.Range("E" & rows.count).End(xlUp).row).Value
arrFact = facturi.Range("A2:F" & facturi.Range("F" & rows.count).End(xlUp).row).Value
Debug.Print UBound(arrP): Stop
For a = 1 To UBound(arrFact)
nrComanda = arrFact(a, 6)
Set cellMatch = rngE.Find(What:=nrComanda, After:=rngE.cells(1, 1), LookIn:=xlValues, lookAt:=xlWhole)
If Not cellMatch Is Nothing Then
arrP(cellMatch.row, 1) = arrFact(a, 1)
End If
Next a
camion.Range("P1").Resize(UBound(arrP), 1).Value = arrP
MsgBox "Ready..."
End Sub
Please, send some feedback after testing it...
A VBA Lookup: Using Arrays and a Dictionary
Option Explicit
Sub CopiazaNrFact()
Dim wb As Workbook: Set wb = ThisWorkbook
' Write the values from the Source Compare and Value ranges to arrays.
' f - Facturi (Source), c - Compare, v - Value
Dim frg As Range, fcData() As Variant, fvData() As Variant, frCont As Long
With wb.Sheets("EVIDENTA FACTURI")
' Compare
Set frg = .Range("F2", .Cells(.Rows.Count, "F").End(xlUp))
frCont = frg.Rows.Count
fcData = frg.Value ' write to array
' Value
Set frg = frg.EntireRow.Columns("A")
fvData = frg.Value ' write to array
End With
' Write the unique values from the Source Compare array to the 'keys',
' and their associated values from the Source Values array to the 'items'
' of a dictionary.
Dim fDict As Object: Set fDict = CreateObject("Scripting.Dictionary")
fDict.CompareMode = vbTextCompare
Dim fr As Long, NrFacturi As String
For fr = 1 To frCont
NrFacturi = CStr(fcData(fr, 1))
If Len(NrFacturi) > 0 Then ' exclude blanks
fDict(NrFacturi) = fvData(fr, 1)
End If
Next fr
' Write the values from the Destination Compare range to an array
' and define the resulting same-sized Destination Value array.
' c - Camion (Destination), c - Compare, v - Value
Dim crg As Range, ccData() As Variant, cvData() As Variant, crCont As Long
With wb.Sheets("B816RUS")
' Compare
Set crg = .Range("E4", .Cells(.Rows.Count, "E").End(xlUp))
crCont = crg.Rows.Count
ccData = crg.Value ' write to array
' Value
Set crg = crg.EntireRow.Columns("P")
ReDim cvData(1 To crCont, 1 To 1) ' define
End With
' For each value in the Destination Compare array, attempt to find
' a match in the 'keys' of the dictionary, and write the associated 'item'
' to the same row of the Destination Value array.
Dim cr As Long, NrCamion As String
For cr = 1 To crCont
NrCamion = CStr(ccData(cr, 1))
If fDict.Exists(NrCamion) Then cvData(cr, 1) = fDict(NrCamion)
Next cr
' Write the values from the Destination Value array
' to the Destination Value range.
crg.Value = cvData
End Sub

VBA For loop within IF and For Loop

I'm trying to write a macro to put the name of the steward in a cell if they are assigned to that category. I wrote this code so far but it isn't working. I'm trying to get it so that if a cell of a column in one worksheet matches the cell of another worksheet and if it does, then it will print the name of the steward in a separate cell to identify that that category is owned by that person.
The numbers are in the worksheet Demetri in the range of E27 to E38 and I want to see if the cells in the range BE4 to BE163803 from the worksheet Share_Dump are in the range from the Demetri worksheet.
Sub steward_products()
Dim d, s As Worksheet
Set d = Worksheets("Demetri")
Set s = Worksheets("Share_Dump")
For i = 4 To 163803 Step 1
For j = 27 To 38 Step 1
If s.Cells(i, 3) = d.Cells(j, 5) Then
s.Cells(i, 57) = "Demetri"
End If
Next j
Next i
Please try this code. I think it will do what you need.
Option Explicit
Sub Steward_Products()
' 236
' use descriptive names and use the declarations to explain them
' use Option Explicit and capitalization to avoid typos
Dim WsSteward As Worksheet ' Demetri
Dim WsDump As Worksheet ' Share_Dump
Dim Fnd As Range
Set WsSteward = Worksheets("Demetri")
Set WsDump = Worksheets("Share_Dump")
With WsDump
' presuming that columns 28:38 are not longer than column 27
Set Fnd = .Range(.Cells(4, 27), .Cells(.Rows.Count, 27).End(xlUp)) _
.Resize(, 12)
Set Fnd = Fnd.Find(WsSteward.Cells(5, "J").Value, _
LookIn:=xlValues, LookAt:=xlWhole)
If Fnd Is Nothing Then
MsgBox "Product """ & WsSteward.Cells(5, 10).Value & """ wasn't found.", _
vbInformation, "Invalid product description"
Else
.Cells(Fnd.Row, 57) = "Demetri"
End If
End With
End Sub

Place sum beneath each column in range in Excel

I have code that will clear everything below the "----" on a spreadsheet full of data. The "----"comes from an export into excel and I don't want data located under it, so I clear it.
After the code clears everything underneath the "----", I want to sum each column in a range and then place each column total underneath its column of data. The column range is F thru T. I'd like to be able to change this range in the code for other projects.
The row may not be the same each time, so the code must sum the columns after the last row of data.
Can anyone help with this, thanks!
Sub Remove_everything_under()
Dim mtch As Long
mtch = 0
On Error Resume Next
mtch = Application.WorksheetFunction.Match("----", ActiveSheet.Range("A:A"), 0) + 0
On Error GoTo 0
If mtch > 0 Then
ActiveSheet.Range("A" & mtch, ActiveSheet.cells(Rows.Count, Columns.Count)).ClearContents
End If
End Sub
Sum-up Variable Sized Column Ranges
Description
Adjust the values in the constants section.
You can easily rewrite the procedure to use some of the constants as arguments for multi-purpose use.
The following will sum up the columns defined by cAddress and put the results (sums) to the cells below each non-empty column range. Executing it again will double the previous result each next time.
Some Challenges
Sum will fail if an error value so the cells of the column range have to be looped through. Solved.
Sum will sum up date values. Not solved, but not an issue when looping.
The loop will sum up TRUE as -1. Solved, but not an issue when Sum is used.
Option Explicit
Sub sumupVariableSizedColumnRanges()
Const cAddress As String = "F:T" ' Columns Address
Const FirstRow As Long = 2 ' First Row
Const hasDates_Slow As Boolean = True ' If 'True', then loop always.
Dim frOffset As Long: frOffset = FirstRow - 1 ' First Row Offset
Dim rg As Range ' Initial Range: from FirstRow to last worksheet row.
With ActiveSheet.Columns(cAddress)
Set rg = .Resize(.Rows.Count - frOffset).Offset(frOffset)
'Debug.Print "Initial Range address = " & rg.Address(0, 0)
End With
Dim crg As Range ' Column Range
Dim rrg As Range ' Result Range
Dim lCell As Range ' Last Cell (Range)
Dim cError As Long ' Current Error Number
Dim Result As Double ' Result
' If error, then loop.
Dim Data As Variant ' Data Array
Dim cValue As Variant ' Current Value
Dim r As Long ' Data Array Rows Counter
' Starting idea if same last row for all columns:
' Set lCell = rg.Find("*", , xlFormulas, , xlByRows, xlPrevious)
' If lCell Is Nothing Then Exit Sub
' Set rg = rg.Resize(lCell.Row - frOffset)
' Debug.Print "Processing Range address = " & rg.Address(0, 0)
For Each crg In rg.Columns
Set lCell = crg.Find("*", , xlFormulas, , , xlPrevious)
If Not lCell Is Nothing Then
Set rrg = crg.Resize(lCell.Row - frOffset)
'Debug.Print "Current Range address = " & rrg.Address(0, 0)
If hasDates_Slow Then
cError = -1 ' Dates are not summed up.
Else
On Error Resume Next ' Sum 'fails' if error values.
Result = Application.Sum(rrg) ' Dates are also summed up.
cError = Err.Number
On Error GoTo 0
End If
If cError <> 0 Then
'Debug.Print "Current Error Number = " & cError
cError = 0
Result = 0
If rrg.Rows.Count = 1 Then
ReDim Data(1 To 1, 1 To 1): Data = rrg.Value
Else
Data = rrg.Value
End If
For r = 1 To UBound(Data, 1)
cValue = Data(r, 1)
If IsNumeric(cValue) Then
If VarType(cValue) <> vbBoolean Then ' exclude TRUE = -1
Result = Result + cValue
End If
End If
Next r
Erase Data
End If
lCell.Offset(1).Value = Result
Set lCell = Nothing
End If
Next crg
End Sub

How to select a range of cells in Excel based on a condition?

I need to select the demand range in sheet 1 corresponding to the part number selected in Sheet 2 of my workbook. So far, I have written the macro to automatically select the part number in sheet 1 when the same part number is selected in sheet no 2. But, I'm having trouble selecting the range corresponding to the part number, which I want to base my calculations on. Can anyone please tell me how to select the range?
Public Sub calculation()
Dim x As Variant
Dim rng As Range
Dim i As Variant
Dim j As Integer
Dim findcell As Range
Dim a_1 As Range
Dim b_1 As Range
Dim rnge As Range
Worksheets("Sheet2").Activate
x = Worksheets("Sheet2").Range("C3").Value
Worksheets("Sheet1").Activate
Set rng = Worksheets("Sheet1").Range("A2:A26")
For Each i In rng
If x = i Then
Set findcell = i
End If
Next i
j = findcell.Select
Set a_1 = ActiveCell.Offset(0, 1)
Set b_1 = ActiveCell.Offset(0, 66)
Worksheets("Sheet2").Range("C9").Value "=AVERAGE(Sheet1!"a_1.Address":"b_1.Address")"
End Sub
Should be able to do something like this:
Public Sub calculation()
Dim f As Range
Set f = Worksheets("Sheet1").Range("A2:A26").Find( _
what:=Worksheets("Sheet2").Range("C3").Value, _
lookat:=xlWhole)
With Worksheets("Sheet2").Range("C9")
If Not f Is Nothing Then
.Formula = "=AVERAGE(Sheet1!" & f.Offset(0, 1).Resize(1, 66).Address & ")"
Else
.Value = "???"
End If
End With
End Sub

Excel VBA - How to find blank cell and sum from active cell up to blank cell

I have the following code to find the first blank cell and sum the data below it at the last blank cell.
Dim r As Range
Dim lngRowStart As Long
If Range("A1").Formula <> "" Then
lngRowStart = 1
Else
lngRowStart = Range("A1").End(xlDown).Row
End If
Set r = Cells(lngRowStart, 1).End(xlDown).Offset(1, 0)
If Left(r.Offset(-1, 0).Formula, 1) <> "=" Then
r.FormulaR1C1 = "=Subtotal(9,R[-" & r.Row - lngRowStart & "]C:R[-1]C)"
End If
But this assumes that the data is in column A and for the first set of continuous data, how to modify it for any active cell to sum the above continuous data?
For example:
2
4
3
Blank (SUM ABOVE=9)
1
3
2
Blank (SUM ABOVE=6)
You can use the UDF below (explanation inside the code's comments):
Function SumContinRange(CurCell As Range) As Double
Dim RngStart As Range, SumRng As Range
If CurCell <> "" Then
' find the first empty cell using the Find function
Set RngStart = Columns(CurCell.Column).Find(what:="", After:=CurCell, LookIn:=xlValues)
Else
' find the first empty cell using the Find function
Set RngStart = Columns(CurCell.Column).Find(what:="", After:=CurCell, LookIn:=xlValues, SearchDirection:=xlPrevious)
End If
' set the Sum Range
Set SumRng = Range(RngStart.Offset(-1, 0), RngStart.Offset(-1, 0).End(xlUp))
SumContinRange = WorksheetFunction.Sum(SumRng) ' return this value
End Function
Then, test it by passing the ActiveCell using the Sub below:
Sub TestFunc()
If ActiveCell.Value <> "" Then
ActiveCell.End(xlDown).Offset(1) = SumContinRange(ActiveCell)
Else
ActiveCell = SumContinRange(ActiveCell)
End If
End Sub

Resources