define dynamic range in vba - excel

I have the following problem:
I am trying to set the range client equal to a dynamically changing range.
In column AI, starting from cell 131, I have a list of clients, which varies in length depending on the years I download data for. I would like to set the range named client equal to this variable range. My code so far is:
Sub range()
Dim client As range
Dim lastrow As Long
Dim startingcell As Long
Set startingcell = range("AI131")
lastrow = Cells(Row.Count, startingcell.Column).End(xlUp).Row
Set client = range(startingcell, Cells(lastrow, startingcells.Column))
End Sub
It is not working though, any suggestions?
Thank you

Looks like you've an error with dimensioning and use of variables not being correct.
This will utilize only As Range which should help resolve the issue:
Dim startcell As Range, endcell As Range, client As Range
Set startcell = Cells(131, "AI")
Set endcell = Cells(Rows.Count, "AI").End(xlUp)
Set client = Range(startcell, endcell)

Related

Using Range(Cell1 value, Cell2 value) - VBA

I'm trying to define a range by the contents of two different cells, each containing the indirect cell addresses. I'm not sure whether it's possible, but here's an example:
Cell X100 contains value $A$1
Cell Y200 contains values $C$5
Is there any way I can use Range() and cells X100 and Y200 to arrive at Range("$A$1:$C$5")?
I've tried using Cells.Address but I can't figure out the right format for the application. Any help is appreciated!
Thanks
Edit
Thank you Tom! I have another question for you. The X100 cell is actually variable in my case, and I was using the following formula to find it:
Cells.Find("ID").Offset(1,0).Address
Is there any way to incorporate this sort of formula into the Range application? Or would it be easier to define a static cell in the spreadsheet containing this formula?
Thanks a bunch
Edit 2
Here you are! I'm dimming r and x as ranges and setting them as follows:
r = Cells.Find("ID").Offset(1,0).Address
x = Cells.Find("Description of initiative").offset(1,0).end(xldown).Offset(0,cells.Find("ID").Column-cells.Find("Description of initiative").Column).address
They're convoluted I know, but I printed them out and they are returning the right cells in the $A$1 format.
Hope this clarifies! Really appreciate your help.
Do you mean
Range(Range("X100").Value2 & ":" & Range("Y200").Value2)
Rather than working with addresses, work with Range objects.
Not sure I fully understand your setup, but something like this is maybe what you're looking for.
Sub Test()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim startCell As Range
Set startCell = ws.Cells.Find(What:="ID") '<--- you should specify the other parameters of Find
Dim endCell As Range
Set endCell = ws.Cells.Find(What:="Description of initiative") '<--- again, specify parameters of Find
If startCell Is Nothing Then Exit Sub '<--- Find was unsuccessful
If endCell Is Nothing Then Exit Sub '<--- Find was unsuccessful
Set startCell = startCell.Offset(1, 0)
Dim columnOffset As Long
columnOffset = startCell.Column - endCell.Column
Set endCell = endCell.Offset(1).End(xlDown)
Set endCell = endCell.Offset(, columnOffset) '<--- there's a simpler way to do this, this just gets you back to startCell.Column, but preserving your logic
Dim myRange As Range
Set myRange = ws.Range(startCell, endCell)
End Sub
Here's the simpler way to get endCell instead of the offset.
Sub Test()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim startCell As Range
Set startCell = ws.Cells.Find(What:="ID") '<--- you should specify the other parameters of Find
Dim endCell As Range
Set endCell = ws.Cells.Find(What:="Description of initiative") '<--- again, specify parameters of Find
If startCell Is Nothing Then Exit Sub '<--- Find was unsuccessful
If endCell Is Nothing Then Exit Sub '<--- Find was unsuccessful
Set startCell = startCell.Offset(1, 0)
Dim lastRow As Long
lastRow = endCell.Offset(1).End(xlDown).Row
Set endCell = ws.Cells(lastRow, startCell.Column)
Dim myRange As Range
Set myRange = ws.Range(startCell, endCell)
End Sub

Copy last row between A and I to row below

I'm trying to look for the last row of data between column A and I and then duplicate the value to the row below which is empty.
Every time I run it, Excel crashes
Sub insert_row()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
LastRow = LastRow
Dim lastrow_start As String
Dim lastrow_end As String
lastrow_start = "A" & LastRow
lastrow_end = "I" & LastRow
Dim lastrowregion As String
lastrowregion = lastrow_start & ":" & lastrow_end
Dim lastrowrange As Range
Set lastrowrange = Range(lastrowregion)
Dim rng As Range
Set rng = Range(lastrow_start)
Do While (rng.Value <> "")
rng.Offset(1).insert
lastrowrange.Copy rng.Offset(1)
Set lastrowrange = rng.Offset(2)
Loop
End Sub
Is it just copying too much and causing a crash? It's only nine columns and they're all text apart from one cell which is a shape (button).
You are trying to set a String to a range object. To get the range use:
Set rng = Range(lastrowregion)
The Range you are getting is A2:I2. So your Do While will error because rng.Value is actually returning an Array. You could either loop through either the Range or the Array at that point if you intended on it being multiple cells.
If the goal is simply to copy the last row of data down one row then this method can be much simpler. You can simply set the Offset to equal the value of the last row. Since they are the same size it will just work.
To show this I used CurrentRegion but you could also do it with your A2:I2 Range.
Public Sub copyLastRowDown()
Dim region As Range
Set region = ThisWorkbook.Worksheets("Sheet1").Range("A1").CurrentRegion
With region.Rows(region.Rows.Count)
.Offset(1).Value = .Value
End With
End Sub
Additional Notes
Use Option Explicit to ensure all variables are explicitly declared.
Declare and assign variables next to where they are going to be used, but place them in a reasonable place.
Do not use underscore case as this has special meaning with events and interfaces.

Selecting range inside For each loop works fine and but if outside the loop, gives error

When I select a range inside a for loop, it works fine:
For Each d1 In Range(Range("B2"), Range("B2").End(xlDown))
To improve the performance of the code, I tried selecting range outside the For Each loop as follows. But it gives me error.
Dim StartCell As Variant
Dim EndCell As Variant
StartCell = Range("B2")
EndCell = Range("B2").End(xlDown)
For Each d1 In Range(StartCell, EndCell)
----
----
Can anyone help in resolving the error?
Your two variables are actually ranges so you need to use the Set statement when assigning such (object) variables. Btw your code will fail if you have nothing underneath B2.
Dim StartCell As Range
Dim EndCell As Range
Set StartCell = Range("B2")
Set EndCell = Range("B2").End(xlDown)
For Each d1 In Range(StartCell, EndCell)

Runtime error 13 :Type mismatch

I am trying to execute a simple code to create a Pivot Table using my data.
Sub PTable()
Dim PT As PivotTable
Dim PTCache As PivotCache
Dim rng As Range
Set rng = Range("A1", Range("A1").End(xlToRight).End(xlDown))
rng.Select
Set PTCache = ActiveWorkbook.PivotCaches.Create(xlDatabase, rng)
Sheets("New").Activate
Set PT = ActiveSheet.PivotTables.Add(PTCache, Range("A1"), "My_PT")
End Sub
Runtime error 13, Type Mismatch is thrown while setting PTCache. This has been happening very frequently whenever I am working with Pivot Tables on my excel using VBA.
This string Set rng = Range("A1", Range("A1").End(xlToRight).End(xlDown)) is setting very huge range "$1:$1048576".
You can watch it in debugger:
Range("A1", Range("A1").End(xlToRight).End(xlDown)).Address
=> "$1:$1048576"
Maybe something wrong with the range, that you want to use in ActiveWorkbook.PivotCaches.Create?
Try also use this Microsoft's advice about second argument PivotCache.Create:
When passing as a range, it is recommended to either use a string to
specify the workbook, worksheet, and cell range, or set up a named
range and pass the name as a string. Passing a Range object may
cause "type mismatch" errors unexpectedly.
Also, you might try
Set rng = Range("A1").CurrentRegion
which is like Ctrl+Shift+* instead of
Set rng = Range("A1", Range("A1").End(xlToRight).End(xlDown))
Performing a single method (i.e., .CurrentRegion) instead of two methods (i.e., xlToRight followed by xlDown) is likely to be less memory intensive and resolve the Type Mismatch glitch.
I had the same issue as you. I had a code working perfectly until the number of rows was over 60.000 lines, then error 13 :Type mismatch appeared when creating the PivotCache...
Solution: Instead of using a Range variable to store the range do it in a string variable. That way (I don't know why) you can avoid having that error. This code should work:
Sub PTable()
Dim PT As PivotTable
Dim PTCache As PivotCache
'Dim rng As Range
Dim LastRow As Long
Dim LastColumn As Long
Dim RangeString As String
Dim SheetName As String
'Set rng = Range("A1", Range("A1").End(xlToRight).End(xlDown))
'rng.Select
LastRow = UsedRange.Rows.Count
LastColumn = UsedRange.Columns.Count
SheetName = ActiveSheet.Name
RangeString = SheetName & "!R1C1:R" & LastRow & "C" & LastColumn
Set PTCache = ActiveWorkbook.PivotCaches.Create(xlDatabase, RangeString)
Sheets("New").Activate
Set PT = ActiveSheet.PivotTables.Add(PTCache, Range("A1"), "My_PT")
End Sub

VBA - How to set the start and end row when setting a range by column numbers

Suppose I set a range of multiple distinct columns by column number like this:
Set rngData = shtData.Range(Columns(1), Columns(2), Columns(5))
But I only want the range to start at for example row 5 and end at row 10.
Can I specify this in the Set rngData statement? Appreciate any help
EDIT.
Thanks to KazJaw this is the solution that worked for me:
Dim shtData, rngData
Set shtData = Worksheets("Data")
Set rngData = Union(shtData.Columns(1), shtData.Columns(2), shtData.Columns(5))
Set rngData = Intersect(rngData, shtData.Rows("5:10"))
There are few possible ways but I'm not sure which would be best for you. My first and possibly simplest proposal is the following:
Set rngData = shtData.Range(Columns(1), Columns(2), Columns(5))
set rngData = Intersect(rngData, shtData.Rows("5:10"))
But, your current range will not work anyway. You could use something like this instead:
Set rngData = shtData.Range("A:B, E:E")
or if you need to keep numeric index of columns than you could go this way (complete code):
Set rngData = Union(shtData.Columns(1), shtData.Columns(2), shtData.Columns(5))
set rngData = Intersect(rngData, shtData.Rows("5:10"))
Edit- to extend and explain: See below subroutine and comments inside
Sub Test_Selection()
'Variant A- select range from column 1 to 5
ActiveSheet.Range(Columns(1), Columns(5)).Select
'Variant B- select range of columns: 1, 2 and 5
With ActiveSheet
Union(.Columns(1), .Columns(2), .Columns(5)).Select
End With
'This will not work
ActiveSheet.Range(Columns(1), Columns(2), Columns(5)).Select
End Sub
So, variant B above is able to select not continuous range like this:
And final explanation about Intesect, for all who are interested. This procedure would give result as presented in the picture below:
Sub Final_Combination()
Dim shtData As Worksheet
Set shtData = ActiveSheet
Dim rngData As Range
Set rngData = Union(shtData.Columns(1), shtData.Columns(2), shtData.Columns(5))
Set rngData = Intersect(rngData, shtData.Rows("5:10"))
'or simply combined in one line of code
Set rngData = Intersect(Union(shtData.Columns(1), _
shtData.Columns(2), _
shtData.Columns(5)), _
Rows("5:10"))
rngData.Select
End Sub

Resources