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
Related
What are the best ways to move excel ranges around using VBA? For as frequently as I need to do it, I still have a lot of trouble with it. I'd like to show my most-used approaches for criticism and/or suggestions of new ways to go about moving ranges.
The cut/copy method seems to be really finicky, especially when multiple worksheets or variables are involved. For example:
Dim wkb1 as Workbook
Dim wks1 as Worksheet, wks2 as Worksheet
Set wbk1 = ThisWorkbook
Set wks1 = wbk1.Worksheets(1)
Set wks2 = wbk1.Worksheets(2)
wks1.Range("A1:A5").Copy (wks2.Range("A1"))
' Error: Object variable or With Block variable not set.
wbk1.Worksheets(1).Range("A1:A5").Copy (wbk1.Worksheets(2).Range("A1"))
' This works.
I would think that avoiding the clipboard increases execution speed. Here, I simply equate one range to another. The drawback is that it requires ranges of equal dimensions:
' Copy a range of two equal dimensions.
WrkSht2.Range("A1:F" & (rngEndRange.row - 10)).Value = _
WrkSht2.Range("A10", rngEndRange).Value
I like the idea of using collections, but there's the draw back of added complexity from needing to work with loops.
Sub UseCollection()
Dim MySheet As Worksheet
Dim lngLastRow As Long
Dim rngSearch As Range, rngCell As Range, rngCopy As Range
Dim MyCollection As New Collection
Set MySheet = ThisWorkbook.Worksheets(1)
Set CopySheet = ThisWorkbook.Worksheets(3)
lngLastRow = MySheet.Range("A1").End(xlDown).Row
Set rngSearch = MySheet.Range("A1:A" & lngLastRow)
Set rngCopy = CopySheet.Range("A1")
For Each rngCell In rngSearch
MyCollection.Add rngCell.Value
Next rngCell
i = 1
For Each Element In MyCollection
rngCopy(i, 1) = Element
i = i + 1
Next Element
End Sub
So how do you all go about copying ranges? Ideally, an approach should be easy to use with worksheet/range variables, and it should be relatively simple.
Yes the range size is a slight faff which is one reason why I often don't bother, but you can do it this way:
Sub x()
Dim r1 As Range
Set r1 = Range("A1:C3")
With r1
Range("F1").Resize(.Rows.Count, .Columns.Count).Value = r1.Value
End With
End Sub
Edit: think this is what BigBen's comment means.
...Or a bit shorter 😎
Sub x()
With Range("A1:C3")
Range("F1").Resize(.Rows.Count, .Columns.Count).Value = .Value
End With
End Sub
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)
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
i have an excel/vba issue which seems to occur in excel2010 but not excel2016. for me it is a non comprehensible conversion between a1 and r1c1 notation.
i have a range that is dynamic
Dim rng As Range
rng = Application.Range("worksheet!A4:A" & _
Worksheets("worksheet").Range("A" & rows.Count).End(xlUp).Row
also i have a name-variable (called "Norm") i use as a dropdown option in cells and would like to update it according to the dynamic range using
With Application.Names("Norm")
.Name = "Norm"
.RefersTo = rng.Address
.Comment = ""
End With
both run on Workbook_BeforeSave.
when saving while in vba editing mode everything works as expected, the name-variable has the correct range in a1-notation and the content of Norm is according to the range.
but saving in pure excel-mode results in the range in r1c1-notation which can not be processed by the name-variable leaving it empty. unfortunately i can't find any explanation or solution for that. is this an excel2010 issue or what can i do about that?
Range is a member of worksheet.
Names us a member of workbook.
You Set a range object.
RefersTo should point to the range object, not its address.
Revised code:
Dim rng As Range
WITH THISWORKBOOK.WORKSHEETS("worksheet")
SET rng = .Range(.cells(4, "a"), .cells(.rows.count, "a").end(xlup))
end with
With thisworkbook.Names("Norm")
.Name = "Norm" 'totally redundant, it already has a name identified in the line above
.RefersTo = rng 'no address, just rng
.Comment = ""
End With
Name has two properties RefersTo and RefersToR1C1, which means that you should assign appropriate address style. If you want to be sure you get correct notation, you should use ReferenceStyle parameter:
Names("Norm").RefersTo = "=" & Range("A1").Address(ReferenceStyle:=xlA1)
Names("Norm").RefersToR1C1 = "=" & Range("A1").Address(ReferenceStyle:=xlR1C1)
First, you are not setting your rng object correctly:
rng = Application.Range("worksheet!A4:A" & _
Worksheets("worksheet").Range("A" & rows.Count).End(xlUp).Row
should give you an error, you need to Set your rng object, see code below:
Dim Sht As Worksheet
Dim Rng As Range, LastRow As Long
' set the worksheet object
Set Sht = ThisWorkbook.Worksheets("worksheet")
With Sht
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' get last row with data in column A
' set the Range object
Set Rng = .Range("A4:A" & LastRow)
End With
' updating the range that "Norm" refres to
With ThisWorkbook.Names("Norm")
.RefersTo = Rng
End With
I am building a module to import text into an Excel workbook. After it imports, I want to format the data as a table. The problem I have is that the import will never have the same range.
I'm using the following code, but it throws an error, Run-time error '424': Object required.
Sub ImportRange()
Dim ws As Worksheet
Dim lRow As Long
Dim lCol As Long
Dim rng As Range
Set ws = ThisWorkbook.Worksheets("Import")
lRow = ws.UsedRange.Row - 1 + ws.UsedRange.Rows.Count
lCol = ws.UsedRange.Column - 1 + ws.UsedRange.Columns.Count
Set rng = ws.Cells(lRow, lCol).Address(True, True)
'MsgBox Cells(lRow, lCol).Address(True, True)
End Sub
I've done quite a bit of searching, but I have been unable to find an answer or figure out how I should be doing this.
The end result would look something like this in the code with the start of the range always being set to $A$1:
ws.ListObjects.Add(xlSrcRange, Range("$A$1:$AM$90"), , xlYes).Name = _
"Import"
If your goal is to set a range to the used range on a sheet, it can be done simpler:
Set rng = ws.UsedRange
Obviously, you need to make sure that the usedrange on that sheet properly represents your imported data.
To convert the range to a table:
Dim Import_Table As ListObject
Set Import_Table = ws.ListObjects.Add(SourceType:=xlSrcRange, Source:=rng, XlListObjectHasHeaders:=xlYes)
Import_Table.Name = "Import"
Note: the code is for Excel 2010. For later versions, replace XlListObjectHasHeaders with HasHeaders