Change dynamic source data for pivot table Excel Macro - excel

I've created a macro that auto updates/changes the source data of my pivot.
The problem with my macro is the source data is not static. The number of rows in trialbalance sheet changes daily so the cell reference A1:F500 is not applicable to what I'm trying to achieve.
The number of column is fixed always (columns A to F).
If someone could lend his or her helping hand on how can I detect how to get the top up to the bottom of the report found in the trialbalance sheet? That would be great!
Sheets("mtd move").pivottables("pvtmtd").SourceData = Sheets("trialbalance").[A1:F500].CurrentRegion.Address(True, True, xlR1C1, True)
ActiveWorkbook.ShowPivotTableFieldList = False

In the comment above, #DougGlancy has a great suggestion. If you are stuck with an older version of Excel that does not support the built-in Table construct, you could use the following to identify the last row, then wrap the entire data block in a Range:
'...
Dim LastRow As Long
Dim PivotSource As Range
With Sheets("trialbalance")
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Set PivotSource = .Range(.Cells(1, 1), .Cells(LastRow, 6)) '<~ col F = 6
End With
You now have a Range object that contains all the data on the "trialbalance" sheet, i.e. all the cells from A1 (.Cells(1, 1) in the snippet above) to the last occupied row in column F (.Cells(LastRow, 6) in the above code).

Related

Autofill Dynamic Column

Trying to Autofill Column X and Column Y with text
Where Column Z determines the table length
Starting cell for column Z is "Z3" but column "X and Y" are dynamic
Last filled cell in column "X & Y" carries the text required.
Current Last cells is "X56" and "Y56"
Current last cell in column Z is "Z89"
I can easily get to x56 or y56 using
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
However the solution eludes me to remove absolute references due to the dynamic nature of the information being imported and added to the column of previous information.
I tried this code i read through my research but couldn't make it work
lastRow = Range("Y3").End(xlDown).Row
Selection.AutoFill Destination:=Range("Y3:Y" & lastRow), Type:=xlFillDefault
Any assistance would be really appreciated as this appears to be the lynch pin to completing this task
Cheers
Mick
with I am trying to stack reports generated on a 12 hourly basis.
into an accrued 24 data table. This will then be accrued into a monthly data table.
As base information is downloaded in csv format. The four reports are formatted differently so i also have to stack the four reports in two table separated and itemised by date and shift.
This then allows the use of lookups, countifs sumifs etc to populate my outputs.
The four reports are dynamic and open to the potential of having a number of blank cells throughout.
I have written code that is robust enough to achieve this short of this one issue.
As the four reports do not have time stamps i am forced to use file names (column A:A) to populate the Date and Shift ranges (column A:B) as well as (Column X:Y) but need to drag the text down to cover all rows of information
Range("Y3").Select
Selection.End(xlDown).Select
Selection.AutoFill Destination:=Range("Y56:Y89")
Range("Y56:Y89").Select
Range("X56").Select
Selection.AutoFill Destination:=Range("X56:X89")
Range("X56:X89").Select
Autofill Columns with text without absolute references to allow for dynamic column range and without known starting point on the column
Do not use xlDown to find the last row. You may want to have a look at this Finding Last Row
Is this what you are trying? I have given you two option. Take your pick.
Option Explicit
Sub SampleA()
Dim ws As Worksheet
Dim lRow As Long
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
'~~> Autofill formula in 1 go
.Range("X3:X" & lRow).Formula = .Range("X3").Formula
.Range("Y3:Y" & lRow).Formula = .Range("Y3").Formula
End With
End Sub
Sub SampleB()
Dim ws As Worksheet
Dim lRow As Long
Dim rng As Range
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
'~~> Get last row in Col Z
lRow = .Range("Z" & .Rows.Count).End(xlUp).Row
Set rng = .Range("X3:Y3")
rng.AutoFill Destination:=.Range("X3:Y" & lRow)
End With
End Sub

I was wondering if there is a way to delete specific rows based on varying column and cell data in Excel VBA

I have a spreadsheet that I regularly use to schedule preventive maintenance. The spreadsheet contains over 4300 rows and 600 columns. This is my master spreadsheet that I use to schedule maintenance.
The columns, starting at "A" contain
Column "A" header "system",
Column "B" header "sub-system",
Column "C" header "asset",
Many columns in the range between column "C" header "Asset" and column "EH" "Name" that contain the weeks for three years and other headers
Column "EH" "Name",
Column "EI" "Date", and
Column "EJ" "Initials".
The cells associated with the weeks that are formatted for dates contain dynamic strings such as "W-1, or IS-3, or E3-1" in dynamic cells up and down the column. I have included a screenshot of an example of what I am looking for. The worksheet is named Schedule as well as the workbook. I would appreciate any assistance that you can provide using VBA to help automate this time consuming process.
That's the intersection of rows with non-blank cells in column C, and rows with blank cells in column D:
Set r = Range("C:C").SpecialCells(xlCellTypeConstants).Offset(, 1)
Intersect(r, r.SpecialCells(xlCellTypeBlanks)).EntireRow.Delete
If I understand your question correctly, you simply want to delete all rows in the sheet, provided a certain criterion in Column D is met? The following code will do it, but please make sure to back up your file before trying it!
Sub deleteRowsBasedOnCriteria()
Dim i As Long, lastRow As Long
Dim sht As Worksheet
Application.ScreenUpdating = False
Set sht = ThisWorkbook.Sheets("test") ' change sheet name to correct one in production
With sht
lastRow = .Cells.Find(What:="*", SearchOrder:=xlRows, SearchDirection:=xlPrevious, LookIn:=xlValues).Row
For i = lastRow To 2 Step -1 ' presuming there are headers at the top in row 1
' if necessary, change the criterion or add more criteria --> this is just based on your example
If .Cells(i, 4).Value <> "X" Then .Rows(i).Delete
Next i
End With
Application.ScreenUpdating = True
End Sub
If you need to delete a really huge number of rows, it is recommended to set a range object instead and then delete them at once as it is more efficient, but I suspect the above code meets your requirements.

Worksheet.UsedRange.Rows.Count returns wrong result

In VB.NET I want to get the used rows so I wrote that:
Dim objWorksheet As Excel.Worksheet = workbook.Sheets(2)
Dim lastRow = objWorksheet.UsedRange.Rows.Count
The number of lastRow is less than used rows. I searched the site and someone suggested:
Dim range As Excel.Range = objWorkSheet.UsedRange
Dim lastRow = range.Rows.Count
This returns less than actual used rows.
The solution is in the image:
I found this question it is an overall understanding of the last used row.
UsedRange.Rows.Count means from the first rows that has data to the last rows that has data, which means you can have empty rows between the first non-empty rows to the last non-empty rows which not affect the result, but if the first row is empty, the result will be one less the actual non-empty row, and if the first two row is empty the result will be two less, so the link question said never use UsedRange.Rows.Count to get the last row.
Try to avoid UsedRange. It can be misleading. For instance, if you fill range A1:B5 and clear the contents of column B, then UsedRange.Columns.Count will return 2 - because Excel remembers cells with formatting and includes them into UsedRange.
UPDATE
To get real last column and row, use following code:
lRealLastRow = _
Cells.Find("*", Range("A1"), xlFormulas, , xlByRows, xlPrevious).Row
lRealLastColumn = _
Cells.Find("*", Range("A1"), xlFormulas, , xlByColumns, xlPrevious).Column
UPDATE 2
Sometimes it only appears too small. Say we have:
and we run:
Sub aRowsByAnyOtherName1()
Dim N As Long
N = ActiveSheet.UsedRange.Rows.Count
MsgBox N
End Sub
We see:
The reason we get 3 rather than 4 is that the top row of the worksheet is not in UsedRange!
EDIT#1:
If the "top" of the worksheet needs to be included then use:
Sub aRowsByAnyOtherName2()
Dim N As Long, rng As Range
Set rng = ActiveSheet.UsedRange
N = rng.Rows.Count + rng(1).Row - 1
MsgBox N
End Sub
This is a bit of a punt on what you mean by "used" rows. If you have any blank rows at the start of the sheet you will get the wrong last row number but you will get the used range row count.
Try the following with row 1 blank.
Option Explicit
Sub test()
Dim rng As Range
Set rng = ActiveSheet.UsedRange
Debug.Print rng.Rows.Count '2
Debug.Print ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row '3
End Sub
This yields 2 from UsedRange.Rows.Count and 3 from using xlCellTypeLastCell with data as below:
I'm using Excel 2013, and as far as I can see the UsedRange and UsedRange.Count Properties work correctly
In previous versions I can remember noticing that they were unreliable, and I think this may be the reasons of some older posts, eg stackoverflow.com/questions/11169445...
Note that the UsedRange is a Single Rectangular Area bounded by the Top-, Right-, Bottom-, and Left-most
Non-Blank Cells, so that the Last Used Row is thus
ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
Note also that UsedRange INCLUDES all Cells that have Any Content, for example a Border, Interior Coloring or a Comment, not just those with a Value or a Formula
Depending on what you are trying to achieve, using the SpecialCells and Find Methods may be preferable; for example the Last Used Row can also be found using
ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
UsedRange does exactly what it is supposed to do in these scenarios. How many rows of data do you have? If you have a block of data in the center of a worksheet with 3 rows and 4 columns, UsedRange returns 3 rows properly. If your worksheet has empty rows in rows 1:3, for example, you must consciously make note of that. UsedRange is very powerful if you format your workbook properly, and even MORE powerful when it's not formatted like that, because it doesn't care where the table is.
As a best practice, you should always have a single, continuous table of data on a spreadsheet starting in cell A1. If you need a summary formatted a few rows and columns in, that should be a separate sheet. And if you get a worksheet from another source that isn't formatted properly, it's your job to fix that before you analyze it -- delete empty rows and columns in front of the table.

Setting a dynamic range to Fill Down

I'm very new to using VBA with my excel workbooks.
I came across the following piece of code that #Manhattan provided as an answer to another question. It suits the needs of my workbook perfectly, but I need help with setting up a dynamic range.
What I am struggling to do now, is make the code only fill down enough rows to match up with the rows in column P (Which is the Row Labels column of the pivot table which the code below is pulling data from), except for the very last row (which is always "Grand Totals")?
Sub FillDown()
Dim strFormulas(1 To 3) As Variant
With ThisWorkbook.ActiveSheet
strFormulas(1) = "=SUM($Q3:$S3)"
strFormulas(2) = "=iferror(index(q3:s3,match($AE$2,$Q$2:$S$2,0)),0)"
strFormulas(3) = "=$AD3-$AE3"
.Range("AD3:AF3").Formula = strFormulas
.Range("AD3:AF150").FillDown
End With
End Sub
TL;DR: How can I make this code only fill down enough rows to match the last row -1 in column P?
Dynamically find the last row of column P (LR):
Dim LR as Long
LR = .Cells( .Rows.Count, "P").End(xlUp).Row
Then apply the last row minus 1 to your filldown:
.Range("AD3:AF" & LR-1).FillDown

Excel VBA set print area to last row with data

I have an Excel table with a sheet "CR" where columns A to K are filled, with the first row being a header row.
Rows 1-1000 are formatted (borders) and column A contains a formula to autonumber the rows when data in column F is entered.
Sheet "CR" is protected to prevent users from entering data in column A (locked).
Using the Workbook_BeforePrint function, I'm trying to set the print area to columns A to K and to the last row of column A that contains a number.
My code (in object 'ThisWorkbook') is as follows:
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("CR")
' find the last row with data in column A
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
ws.PageSetup.PrintArea = ws.Range("A1:K" & lastRow).Address
End Sub
However, when I click File -> Print, the range of columns A to K up to row 1000 is displayed instead of only the rows that have a number in column A. What am I doing wrong?
Change:
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
To:
lastRow = [LOOKUP(2,1/(A1:A65536<>""),ROW(A1:A65536))]
.End(...) will act like ctrl + arrow-key. if the cell has a formula (which looks empty due to the formula, then it will still stop there... another way would be the use of evaluate (if you do not want to loop) like this:
lastRow = .Evaluate("MAX(IFERROR(MATCH(1E+100,A:A,1),0),IFERROR(MATCH(""zzz"",A:A,1),0))")
This will give the last row (which has a value in column A).
Also check if there are hidden values (looking empty due number format or having characters you can't see directly. Try to go below row 1000 in column A (select a cell after A1000 in column A) and hit ctrl+up to validate where it stops (and why).
EDIT:
(regarding your comment)
"" still leads to a "stop" for the .End(...)-command. So either use my formula, translate the formula into vba or loop the cells it get the last value. Also Find is a good tool (if not doing it over and over for countless times).
lastRow = .Cells.Find("*", .Range("B1"), xlValues, , xlByColumns, xlPrevious).Row

Resources