I'm trying to define a named range in Excel using VBA.
Basically, I have a variable column number. Then a loop runs to determine the first empty cell in that particular column.
Now I want to define a named range from row 2 of that particular column to the last cell with data in that column (first empty cell - 1).
For example, column 5 is specified, which contains 3 values. My range would then be (2,5)(4,5) if I'm correct.
I'm just wondering how to specify this range using only integers instead of (E2:E4).
Is it at all possible?
I found this code to define a named range:
'Change the range of cells (A1:B15) to be the range of cells you want to define
Set Rng1 = Sheets("Sheet1").Range("A1:B15")
ActiveWorkbook.Names.Add Name:="MyRange", RefersTo:=Rng1
Could anyone nudge me into the right direction to specify this range using integers only?
As your targeting a range of E2:E4 you would need to specify the cell locations. The below function might be of use to you, pass it the column number e.g. 5 and it will retunn the address so 5=E and 27=AA
ColLetter = ColNo2ColRef(colNo)
Set Rng1 = Sheets("Sheet1").Range(ColLetter & "2:" & ColLetter & "4")
ActiveWorkbook.Names.Add Name:="MyRange", RefersTo:=Rng1
Function ColNo2ColRef(ColNo As Long) As String
ColNo2ColRef = Split(Cells(1, ColNo).Address, "$")(1)
End Function
Hope this helps
EDIT: Or:
Set rng = Range(Cells(2, 5), Cells(4, 5)) 'E2:E4
ActiveWorkbook.Names.Add Name:="MyRange", RefersTo:=Rng
or alternatively
Sub test()
Set rng1 = Cells(2, 2) 'B2
Set rng2 = rng1.Resize(3, 1) 'B2:B4
'or
Set rng2 = Range(rng1, Cells(4, 2)) 'B2:B4
End Sub
or do it directly without looping using
With Sheet1
col = 5 'variable col
Set rng1 = .Range(.Cells(2, col), .Cells(.Rows.Count, col).End(xlUp))
End With
which is the same as
with sheet1
Set rng1 = .Range(.Range("E2"), .Range("E" & .Rows.Count).End(xlUp))
end with
EDIT: If you're setting up named ranges to change dynamically then you don't need VBA. Enter this directly into the named range in Excel and leave it to auto adjust automatically between E2 and whatever the last item is (assuming no blanks). =$E$2:INDEX($E$2:$E$5000,COUNTA($E$2:$E$5000)) (Extend 5000 if you need need more rows)
Related
I have a piece of VBA code that sorts through a worksheet and deletes all rows that in which one of the columns does not contain specific values
Sub DeleteRows()
' Defines variables
Dim Cell As Range, cRange As Range, LastRow As Long, x As Long, TestRange As Range, MyRange As Range
' Defines LastRow as the last row of data based on column C
LastRow = Sheets("Sheet1").Cells(Rows.Count, "C").End(xlUp).Row
' Sets check range as E1 to the last row of C
Set cRange = Range("C1:C" & LastRow)
' For each cell in the check range, working from the bottom upwards
For x = cRange.Cells.Count To 1 Step -1
With cRange.Cells(x)
' If the cell does not contain one of the listed values then...
If .Value <> "Location1" And .Value <> "Location2" And .Value <> "Location3" Then
' Delete that row
.EntireRow.Delete
End If
End With
' Check next cell, working upwards
Next x
End Sub
The problem is I have a very long and growing list of locations. Instead of specifying locations (e.g., "Location1", "Location2", etc.), I want the code to compare each cell in the check range against a named list ("ReferenceLocations") and delete the row if the cell contains a location name not in that list.
How can I change that section of code (if .value<>...) to achieve this?
Using Application.Match and IsError:
If IsError(Application.Match(.Value, Range("ReferenceLocations"), 0)) Then
.EntireRow.Delete
End If
This assumes that your named range is a single row or column. If that is not a safe assumption, then:
If Application.CountIfs(Range("ReferenceLocations"), .Value) = 0
.EntireRow.Delete
End If
I have created a for loop to detect where does an empty value appears in range "E7:AB7". Once done that I want to create a Range from E7 to that empty value so it can copy and paste the data from a Master Sheet only within that range.
For example if it detects an empty value in X7 then the Range must be ("E7:X7").
Here is a sample of the code:
Sub Macro5()
For Each cell In Worksheets("Proof").Range("E7:AB7")
If IsEmpty(cell) Then
Dim Cval As Range
Set Cval = Worksheets("Proof").Range(cell.Address)
Exit For
End If
Next
Sheets("MasterSheet").Range("A3:AG5000").AdvancedFilter Action:= _
xlFilterCopy, CopyToRange:=Range("E7" & ":" & Cval), Unique:=False 'Here is where the dynamic range exists
End Sub
Someone have an idea on how to apply it to the Range function?
Thanks!
Please play a little with the code below.
Private Sub Test()
Dim Rng As Range ' dynamic range in row 7
With Worksheets("Proof")
Set Rng = .Range(.Cells(7, "E"), .Cells(7, "E").End(xlToRight))
' use the line below to include the blank in the range
' Set Rng = .Range(.Cells(7, "E"), .Cells(7, "E").End(xlToRight).Offset(0, 1))
End With
' Debug.Print Rng.Address
Sheets("MasterSheet").Range("A3:AG5000").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=Rng, _
Unique:=False 'Here is where the dynamic range exists
End Sub
Set Rng = .Cells(7, "E").End(xlToRight) sets a range of a single cell, defined as the last used cell before a blank cell, looking from E7 to the right. A range from E7 to that cell therefore excludes the blank cell itself. Therefore, in your example, if E7 itself is blank the code will crash or maybe set a range D7:E7, neither of which you want. Therefore you may prefer to include the blank cell in the range as, in fact, your code suggested.
Your code CopyToRange:=Range("E7" & ":" & Cval) has two flaws, at least one of which proved fatal. One is that you calculate the range at the time of using it. In my code the range is prepared before use so that you can check its address before you feed it to the filter. The other flaw is that you don't specify the sheet on which your range is supposed to exist. Therefore it will be on the ActiveSheet which could be any sheet at all. My code, you may argue, doesn't specify the worksheet, either. That isn't entirely true. Try Debug.Print Rng.Worksheet.Name.
I have to copy paste some data from a sheet to another in excel using VBA.
I have been able to copy-paste the first set of data from sheet A to sheet B without issues.
I am now at the point where I need to copy the same cell value in sheet A into a range in sheet B
What I tried was to define the lastcell in sheet B and the first cell in sheet B in order to define the range where the value in sheet A should be copied.
This is the code for lastrow (which is working fine)
Last_Row2 = Sheets("Records").Range("a1").End(xlDown).Row
code for starting cell
legrng = Sheets("Records").Cells(Rows.count, 4).End(xlUp).Offset(1)
code for pasting the value into the range
Range("LegRng & Last_row2").Copy Destination = "cell value in sheet A"
I am receiving an error here:
Range("LegRng & Last_row2").Copy Destination = "cell value in sheet A"
the error is : Method 'Range of object_global' failed
Could you please tell me what I am doing wrong?
thank you for the help/explanation
You have a couple of errors
First, you try to refer to the range which has name LegRng & Last_row2. Such range doesn't exist in your worksheet, it can't exist because this name is illegal.
If you want to set reference to the range containing more than one cell you do it this way:
Sheets("Records").Range(startCell, endCell)
So first you need to set references to startCell and endCell (I assume you want last cell to be also in column 4):
Set startCell = Sheets("Records").Cells(Rows.count, 4).End(xlUp).Offset(1)
Set endCell = Sheets("Records").Cells(Last_Row2, 4)
You can fill range with value using its property Value
rng.Value = "value"
So, at the end your code should look like that:
With Sheets("Records")
Last_Row2 = .Range("a1").End(xlDown).Row
Set startCell = .Cells(Rows.count, 4).End(xlUp).Offset(1)
Set endCell = .Cells(Last_Row2, 4)
.Range(startCell, endCell).value = "cell value in sheet A"
End With
If not wrapped within an If Statement that tests if startCell.Row is less then Last_Row2, the accepted answer will cause issues if re-run, the code will place the value from sheet A in the next cell each time the macro is re-run.
You should always define and assign your variables.
Using Resize allows you to not need endCell.
Removing Offset from the startCell ensures the correct count for Resize
Sub FillInBlankCellsWithValue()
Dim Last_Row2 As Long, startCell As Range
With Sheets("Records")
Last_Row2 = .Range("a1").End(xlDown).Row
Set startCell = .Cells(Rows.Count, 4).End(xlUp)
'Use the If statement to test that the startCell.Row is less then the Last_Row2
If startCell.Row < Last_Row2 Then
'Offset to the first empty cell and resize by subtracting the startCell.Row
'from Last_Row2, to set the range for the value from SheetA.
startCell.Offset(1).Resize(Last_Row2 - startCell.Row).Value = Sheets("SheetA").Range("A1")
'Change the worksheet and paste value's cell range, as needed
End If
End With
End Sub
I am trying to make a macro using the SUMPRODUCT function together with SUMIF.
but when I run the macro I get …
run-time error 13.
I have tryed to make the same function just in a cell looking like this.
=SUMPRODUCT(SUMIF(B2:B3,K15:K18,L15:L18))
and it works fine, so I know the concept is proven.
Sub GrandTotal() 'Finds the last non-blank cell in a single row or column
Dim lRow As Long
Dim lCol As Long
Dim GrandTotal As Variant
Dim MyRg1 As Variant
Dim MyRg2 As Variant
Dim MyRg3 As Variant
'Find the last non-blank cell in column A(1)
lRow = Cells(Rows.Count, 1).End(xlUp).Row
'Find the last non-blank cell in row 1
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
MsgBox "Last Row: " & lRow & vbNewLine & _
"Last Column: " & lCol
'set range
Set MyRg1 = Range("B2:B3")
'set criteria
Set MyRg2 = Range("$K$15:$K$18")
'set sum range
Set MyRg3 = Range("$L$15:$L$18")
For Each cell In Range(Cells(lRow, 2), Cells(lRow, lCol))
GrandTotal = WorksheetFunction.SumProduct(WorksheetFunction.SumIf(MyRg1, MyRg2, MyRg3))
cell.Value = GrandTotal
Next cell
End Sub
I have found some guides how to use the function in VBA and I followed the same princip, also i saw an other post here on stack that showed how to do, and yet I get the error.
hope some kind soul can help
First, each variable that is being assigned a Range object can be declared as a Range, instead of Variant. Also, the ranges that are being passed to SUMIF don't seem correct. The first argument or criteria range should be the same size as the third argument or sum range. So I am going to assume that the ranges assigned to MyRg1 and MyRg2 should be the other way around. So to start with we should have the following...
Dim MyRg1 As Range
Dim MyRg2 As Range
Dim MyRg3 As Range
'set criteria range
Set MyRg1 = Range("$K$15:$K$18")
'set criteria
Set MyRg2 = Range("B2:B3")
'set sum range
Set MyRg3 = Range("$L$15:$L$18")
Secondly, you won't be able to use WorksheetFunction.Sumproduct that way. You can, however, use the Evaluate method..
GrandTotal = Evaluate("SUMPRODUCT(SUMIF(" & MyRg1.Address & "," & MyRg2.Address & "," & MyRg3.Address & "))")
Note, though, the Evaluate method has a limitation. It does not accept more than 255 characters. In any case, since you want to transfer the result to a cell, you can first enter the actual formula in the cell, and then convert it into a value...
With cell
'enter the formula in the current cell
.Formula = "=SUMPRODUCT(SUMIF(" & MyRg1.Address & "," & MyRg2.Address & "," & MyRg3.Address & "))"
'convert the formula into a value
.Value = .Value
End With
Hope this helps!
After you have your function working, you can turn on the Macro Recorder, click the cell with the function you need, hit F2, and hit Enter. You will have VBA that does what you want.
Error 13 is a Type mismatch error. I looked up the documentation of WorksheetFunction.SumIf. It says the first argument should be of type Range, and the second and third a Variant. I can not test now, but try to declare MyRg1 as a Range.
This would be a good use for ConvertFormula since you have successfully built the formula in Excel, you just need VBA to generate the value. Note that convertformula cannot handle formulas over 255 characters.
Here's roughly how you could apply it. It's
Sub heresExample()
'formula with the cell in exitance
Dim fCell As Range
Set fCell = Range("G10") 'set this up with a formula that works for
'if you were to copy paste formula.
'Your original code modified
Dim cell As Range
For Each cell In Range(Cells(lRow, 2), Cells(lRow, lCol)).Cells
'Takes the formula and applies the value if from that exact cell.
'(you don't really need grand total)
GrandTotal = Evaluate(Application.ConvertFormula(fCell.Formula2R1C1, xlR1C1, xlA1, , cell))
cell.Value = GrandTotal
Next cell
End Sub
I am trying to get the row number of a cell in a range that I specify with vba. I want to get the row number of the cell in the range but what I am getting is the row number of the cell in the worksheet.
This is the vba code I am using currently. I have set a range and within the range I search for a cell that contains the text string "C". Once I have found the cell I want to make changes to the value in the second column of the range.
Sub trial2()
Dim ActiveWB As Workbook
Dim ActiveWS As Worksheet
Dim rng As Range, findCell As Range
Set ActiveWB = ActiveWorkbook
Set ActiveWS = ActiveWB.ActiveSheet
Set rng = ActiveWS.Range("B4", "C10")
With rng
Set findCell = .Cells.Find(what:="C")
End With
rng.Cells(findCell.Row, 2).Value = "change to something."
End Sub
Before running the code:
After running the code:
the cell value that contains "C" is in the 6th row of the worksheet, but in the 3rd row of the range. I was wondering how do I get the 3rd row of the range. I am aware that I can just offset the cell by 1 column to solve this problem, but I am curious about getting row numbers of cells in respect to a defined range.
One option is to adjust based on the number of the first row of rng, using simple math.
rng.Cells(findCell.Row - rng.Row + 1, 2).Value = "change to something."
In this case 6 - 4 + 1 = 3.
You can use:
Option Explicit
Sub test()
Dim rng As Range
With ThisWorkbook.Worksheets("Sheet1")
'If your searching area for A,B,C etc is from B4 to B10 just use
Set rng = .Range("B4:B10").Cells.Find(what:="C")
'If your searching area for A,B,C etc is from B4 to C10 just use
Set rng = .Range("B4:C10").Cells.Find(what:="C")
If Not rng Is Nothing Then
'Way 1
.Cells(rng.Row, rng.Column + 1).Value = "change to something."
'Way 2
rng.Offset(0, 1).Value = "change to something."
Else
MsgBox "No ""C"" found."
End If
End With
End Sub