Dynamically adjust range based on last column in vba - excel

I have a table in excel where i am inserting some column, because of that last column is getting changed, I have to detect the last column and set it as a range in vba
I have written code to find the last column and convert it to alphabet, however i am not able to set it as a range.
Public Function ColumnLetter(ColumnNumber As Long) As String
ColumnLetter = Split(Cells(1, ColumnNumber).Address(True, False), "$")(0)
End Function
Dim Rng As Range
Dim LastColumn, LastRow As Long
Dim Str As String
LastRow = Cells(Rows.Count, 2).End(xlUp).Row
LastColumn = Cells(2, Columns.Count).End(xlToLeft).Column
Str = ColumnLetter(LastColumn)
'Set Rng = Range("M7:M" & LastRow)
I want to write Commented line as
Set Rng = Range( & Str & "7" & LastRow)
To make it dynamic
How can i do this?

First, change Str to something else; you're shadowing the Str function.
Dim colLetter As String
colLetter = ColumnLetter(LastColumn)
Then concatenate as necessary:
Set Rng = Range(colLetter & "7:" & colLetter & LastRow)
Note that you can skip using the column letter and just use Cells with the column index.
Set Rng = Range(Cells(7, LastColumn), Cells(LastRow, LastColumn))

As others pointed out, Str isn't the best variable name. Let's say you change it to "ColLtr" ... then your specific answer is Range(ColLtr & "7:" & ColLtr & LastRow)
However, might I suggest another tack?
If you are trying to set the range as the lower right corner of the used range, use:
With {sheet}.UsedRange
Set Rng = .Cells(.Rows.Count,.Columns.Count)
End With
(substitute {sheet} with WorkSheets("MySheet") or ActiveSheet or however you prefer to specify the worksheet.)
If you need the entire column, adjust it to:
With {sheet}.UsedRange
Set Rng = .Columns(.Columns.Count)
End With
BUT ... if you "Format Range as a Table" (creating a ListObject), you can bypass VBA altogether and use [TableName[ColumnHeader]], either in VBA or in your worksheet formulae. Of course, "TableName" and "ColumnHeader" would be specific to your table's name and the actual text in your column header.

Related

How can I turn a Range ("A1:A11") into (A"1: until empty cell")

I have tried to just set the range to ("A:A") but that makes the table too large and my computer freezes up, I have also tried to input a line like Range("A" & Rows.Count).End(xlUp).Offset(1) but that is not recognized by VBA.
Any help would be appreciated!
You need to first define your last row by referencing the last cell in the column then use .End(xlUp).row to find the last row number. You can then use that row number to build cell references, or even save the range as a range variable like I did:
Sub Last_Row_Example()
Dim LastRow As Long 'Last Row as a long integer
Dim RG As Range 'A range we can reference again and again very easily
'Consider renaming it to something more descriptive.
'for your particular situation
LastRow = Range("A" & Rows.Count).End(xlUp).Row ' Here we store the "LastRow" Number
Set RG = Range("A1:A" & LastRow) ' Here we build a range using the LastRow variable.
RG.Select
Application.CutCopyMode = False
ActiveSheet.ListObjects.Add(xlSrcRange, RG, , xlYes).Name = _
"Table3"
Range("Table3[[#All],[Ticker Name]]").Select
Selection.ConvertToLinkedDataType ServiceID:=268435456, LanguageCulture:= _
"en-US"
End Sub

VBA Named columns

I have a worksheet named "garcat_nv" with hundreds of columns. The first row contains the names that I'd like to give to each column. How can I loop through my sheet to give each column the name given in the first cell of that column ? This is an example of the Column AJ that I'd like to name GCFRRE.
Dim GCFRRE As Range
LastRow = garcat_nv.Cells(Rows.Count, 1).End(xlUp).Row
Set GCFRRE = Range("AJ2:AJ" & LastRow)
garcat_nv.Names.Add Name:="GCFRRE", RefersTo:=GCFREE
I attempted this loop:
Dim i As Long
Dim rng As Range
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To nbr_col Step 1
Set rng = Range("i2:i" & LastRow)
.Names.Add Name:=.Cells(1, i).Value, RefersTo:=rng
Next i
I get a 1004 error. How can this be solved ? Thanks.
The RefersTo parameter should be a string rather than a range - the string being the address of the range. Sample code might look something like this (but you might want to stick to your lastRow method rather than UsedRange):
Dim col As Range
For Each col In Sheet1.UsedRange.Columns
With Sheet1.Names 'or ThisWorkbook.Names for global scope.
'Remove any existing name.
On Error Resume Next
.Item(CStr(col.Cells(1))).Delete
On Error GoTo 0
'Add the new name.
.Add _
Name:=col.Cells(1).Value, _
RefersToR1C1:="=" & col.Address(ReferenceStyle:=xlR1C1)
End With
Next

Trying to find the value of a cell in column b of the last row in sheet1

I need to find the value of the last cell in column b of sheet1. This value will change weekly. I then want to take that value and find it in sheet2. Then I want to copy and paste all data below this found value to sheet3. I can't get past the first part with the following code:
Dim cell As Range
Dim rangefound As Integer
Dim lastRow As Long
lastRow = ActiveSheet.Range("B" & Rows.Count).End(xlUp).Row
Set cell = Range("B:B").Find("rangefound")
rangefound = lastRow = Cells(lastRow, 2).Value
I've been struggling with the syntax for a month and really don't know what I'm doing.
try this
Sub test()
Dim cell As Range
Dim rangefound As Integer
Dim lastRow As Long
lastRow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
rangefound = Sheet1.Cells(lastRow, 2).Value
Set cell = Sheet2.Range("B:B").Find(rangefound)
MsgBox "The value was found in Sheet2!" & cell.Address
End Sub
The issues with your code were
using rangefound before it had a value, i.e. the order of the commands
using "rangefound" as a text instead of the variable
wrong syntax to assign a value to rangefound
not qualifying which sheet should be searched
Edit: To extend the code to copy the data below the found value to another sheet, use Offset to reference one row below. There are many different ways to do this, so using Offset is just one option.
Here is the complete code
Sub test()
Dim mycell As Range, RangeToCopy As Range
Dim rangefound As Integer
Dim lastRow As Long
lastRow = Sheet1.Range("B" & Rows.Count).End(xlUp).Row
rangefound = Sheet1.Cells(lastRow, 2).Value
' this is the cell with the found value
Set mycell = Sheet2.Range("B:B").Find(rangefound)
' now find the last row in Sheet2. We can use lastRow again,
' since it is no longer needed elsewhere
lastRow = Sheet2.Range("B" & Rows.Count).End(xlUp).Row
' set the range to copy to start one cell below rangefound
' to the end of the data in column B
Set RangeToCopy = Sheet2.Range(cell.Offset(1, 0), Sheet2.Cells(lastRow, "B"))
' copy the range and paste into Sheet3, starting at A1
RangeToCopy.Copy Sheet3.Range("A1")
End Sub
Note: I changed the variable name from "cell" to "mycell". It's better to use variable names that cannot be mistaken for Excel artifacts.
Another edit: If you need to paste into the next free row in Sheet3, use the techniques already established.
[...]
Set RangeToCopy = Sheet2.Range(cell.Offset(1, 0), Sheet2.Cells(lastRow, "B"))
' get the next available row in Sheet3
lastRow = Sheet3.Range("A" & Rows.Count).End(xlUp).Row + 1
' copy and paste
RangeToCopy.Copy Sheet3.Range("A" & lastRow)
[...]
Note that I'm using the same variable for three different purposes. If that is too confusing, create three distinct variables instead.

Excel VBA offset function

I have an Excel file with information in column A and column B. Since these columns could vary in the number of rows I would like to use the function offset so that I could print the formula in one time as an array rather than looping over the formula per cell (the dataset contains almost 1 million datapoints).
My code is actually working the way I want it to be I only can't figure out how to print the code in Range(D1:D5). The outcome is now printed in Range(D1:H1). Anybody familiar how to use this offset within a for statement?
Sub checkOffset()
Dim example As Range
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
Set example = Range("A1:A1")
For i = 1 To LastRow
example.Offset(0, i + 2).Formula = "=SUM(A" & i & ":B" & i & ")"
Next i
End Sub
Using the Offset(Row, Column), you want to offset with the increment of row (i -1), and 3 columns to the right (from column "A" to column "D")
Try the modified code below:
Set example = Range("A1")
For i = 1 To LastRow
example.Offset(i - 1, 3).Formula = "=SUM(A" & i & ":B" & i & ")"
Next i
One way of outputting the formula in one step, without looping, to the entire range, is to use the R1C1 notation:
Edit: Code modified to properly qualify worksheet references
Option Explicit
Sub checkOffset()
Dim example As Range
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
With sht
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set example = .Range(.Cells(1, 1), .Cells(LastRow, 1))
End With
example.Offset(columnoffset:=3).FormulaR1C1 = "=sum(rc[-3],rc[-2])"
End Sub
You don't need to use VBA for this. Simply type =sum(A1:B1) in cell D1 and then fill it down.
If you're going to use VBA anyway, use this:
Sub checkOffset()
Dim example As Range
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Worksheets("Sheet1")
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
Set example = Range("A1:A1")
For i = 1 To LastRow
example.Offset(i - 1, 3).Formula = "=SUM(A" & i & ":B" & i & ")"
Next i
End Sub
The way offset works is with row offset, column offset. You want the column to always be fixed at 3 to the right.

Extract 1st letter from cell concatenate with another cell paste in third cell, then next row

I need to extract 1st letter from cell B2 concatenate with cell C2 paste in cell A2,
then move to next row and repeat till last data row.
I have the following, which partially works, but only works for the first row A2 then fills down this one string through all the rows till last data row.
Sub UserName()
Dim rng As range
Dim lastRow As Long
With Sheets("sheet1")
lastRow = .range("E" & .Rows.Count).End(xlUp).Row
End With
For Each rng In Sheets("Sheet1").range("A2:A" & lastRow)
rng.Value = fUserName(rng.Value)
Next
End Sub
The function
Function fUserName(ByVal strUserName As String) As String
Dim r As String
r = range("B2").Select
strUserName = Left(Trim(r), 1) & " " & range("C2")
fUserName = strUserName
End Function
IMHO you don't need VBA for that. Just use formula in A2
=CONCATENATE(LEFT(B2, 1),C2)
And then just replicate it for all cells that contain data.
Try below code. I have combined both your procedure.
No need of using a function , No need of For each loop
Sub UserName()
Dim lastRow As Long
With Sheets("sheet1")
lastRow = .Range("C" & .Rows.Count).End(xlUp).Row
End With
Range("A1:A" & lastRow).FormulaR1C1 = "= left(RC[1],1) & RC[2]"
End Sub
Your function is wrong, you are passing strUserName to the function but then setting the same variable within the function, however the real source of your issue is that you are using static references in your function so it does not matter which cell your sub routine is dealing with the function looks a cells B2 and C2.
I would get rid of the function all together and just replace the line
rng.Value = fUserName(rng.Value)
With
rng.Value = Left(Trim(rng.offset(0,1)), 1) & " " & rng.offset(0,2)
If you really want to use a function you need to pass the range to the function, not the value of the active cell as this has no bearing on the values of the other cells around it.
You need to pass the range into the function:
Sub UserName()
Dim rng As range
Dim lastRow As Long
With Sheets("sheet1")
lastRow = .range("E" & .Rows.Count).End(xlUp).Row
End With
For Each rng In Sheets("Sheet1").range("A2:A" & lastRow)
rng.Value = fUserName(rng)
Next
End Sub
Function fUserName(rn as Range) As String
fUserName = Left(Trim(rn(1,2).value), 1) & " " & rn(1,3).value
End Function
Well obviously B2 and C2 are hardcoded values so they do not change. You need to make those change by using a range object, for instance. Here's a pseudo-code of what I would do. I leave it up to you to make the necessary adjustments to make it work (because I don't see much effort in your question).
Function fUserName(rng as Range) as String
fUserName = Left(Trim(rng.Offset(0, 1).value), 1) & " " & rng.Offset(0, 2).value
End Function
Instead of calling fUserName() with rng.value, just put in rng. This will use the range object to get the proper rows for B and C.
Following code select first blank row
Sub SelFrstBlankRow()
Dim r1 As Range, r2 As Range, r3 As Range
Set r1 = Sheets("Sheet1").Range("a20")
Set r2 = Sheets("Sheet1").Range("u20")
Set r3 = Range(r1.End(xlUp), r2.End(xlUp)) 'r3 is the 1st blank row
r3.Select
End Sub

Resources