Excel VBA Loop Through a PivotTable and perform calculation - vba

I have a PivotTable that automatically refreshes every time I refresh a data set to our mySQL database in our office.
My Excel file launches a query against the mySQL database and returns a data table, and I have two PivotTables on separate sheets that will automatically update every time that is done. My code for that is below:
Sub UpdatePivots()
' This sub is intended to update all pivot charts in the by switching to the appropriate
' worksheet, locating the appropriate pivot table, and updating them.
Dim ws As Worksheet
Dim PT As PivotTable
For Each ws In ActiveWorkbook.Worksheets '<~~ Loop all worksheets in workbook
For Each PT In ws.PivotTables '<~~ Loop all pivot tables in worksheet
PT.PivotCache.Refresh
Next PT
Next ws
End Sub
What I am looking to do calculate a YIELD for some of the fields in the Pivot Table. The table currently looks like this below:
As you can see, I added in the "YIELD" column automatically and simply did an:
=GETPIVOTDATA("Pass / Fail",$B$5,"Job ID","Job 1","Pass / Fail","Pass")/GETPIVOTDATA("Pass / Fail",$B$5,"Job ID","Job 1")
Ideally, what I would like to do is add to my UpdatePivots() macro to automatically calculate the yield (Pass / Grand Total) for each of the rows listed.
This table is subject to change in size - sometimes I am looking at only 3 jobs in a given month (like September so far), other times my boss wants me to run this report for an entire year where I can have an upwards of 100 jobs. So I would like to use some pseudo code that might look like this:
Cell F6.Text = YIELD
<Apply Pivot Table Formatting to Cell F6>
for each row in pivottable {
Cell Fx.Value = Pass / Grand Total
}
Can anybody help me do that? I have tried brainstorming on paper, but don't even know where to start.
PS - How can I get the Pivot Table to stop that terrible formatting, and to keep my grayed cells? I want to eventually add in charts.
Thank you!!

The following code satisfies my need:
Sub CalculateYield()
k = Cells(Rows.Count, 2).End(xlUp).Row
For r = 9 To k
Cells(r, 6).Formula = "=" & Cells(r, 3).Address(False, False) & "/" & Cells(r, 5).Address(False, False)
Next
End Sub

Related

Excel VBA Code for small scroll while there is a value on the right

I have a Macro that takes data out of 2 reports.
in the second report I have dates that I copy. I need to take a date and subtract from it 14 days
I go to first blank cell in column D, then I want to calculate the formula in column C and scroll down without type how many cells (because it is a macro to a daily basis and the amount of data will change). I want to do this until the end of the data I copied.
In the end I want to copy it as values to column B.
Here is what I have in my code(part of all macro):
'first we go to the buttom of the column
'for NOW - change manually the top of the range you paste to
'Now, paste to OP_wb workbook:
OP_wb.Sheets("Optic Main").Range("D1").End(xlDown).Offset(1, 0).PasteSpecial
Paste:=xlPasteValues
' Calculate Due Date to MFG tools
' it means date we copied from MFG daily minus 14 days
_wb.Sheets("Optic Main").Activate
Range("C1").End(xlDown).Offset(1, 0).Activate
ActiveCell.FormulaR1C1 = "=RC[1]-14"enter code here
You need to loop from the first row to the last row. In general, there are plenty of good ways to define the last row of a given column. Once you have done it, replace the value of lngEndRow and run the following code:
Option Explicit
Public Sub TestMe()
Dim lngStartRow As Long: lngStartRow = 1
Dim lngEndRow As Long: lngEndRow = 100
Dim rngMyRange As Range
Dim rngMyCell As Range
With ActiveSheet
Set rngMyRange = .Range(.Cells(lngStartRow, 5), .Cells(lngEndRow, 5))
End With
For Each rngMyCell In rngMyRange
rngMyCell.FormulaR1C1 = "=RC[1]-14"
Next rngMyCell
End Sub
Then change the ActiveSheet with the correct sheet and the column hardcoded as 5 with the correct one. Run the code above in an empty Excel, to understand what it does. Then change it a bit, until it matches your needs.

Excel defining range across 100+ sheet tabs, remove duplicates in column for 100+ Sheets

Use case: I want to copy data from column A to Column B (where column A, B are arbitrary columns). Once the data is in Column B, I want to remove duplicate entries within column B.
Make a loop that moves data from column A to column B and then removes duplicates for each sheet in a workbook.
`Sub Copy()
For i = 1 To Sheets.Count
Worksheets(i).Range("A1:A100")
Destination:=Worksheets(i).Range("B1")
Next
End Sub
`
For testing I separated the tasks into two different Sub(). Sub Copy() is working and correctly copies my data. Sheet1 is also named "Sheet1" for my specific workbook
`Sub RemoveStuff()
Dim rng As Range
For j = 1 To Sheets.Count
Set rng = Worksheets("Sheet1").Range(Range("B1"),Range("B1").End(xlDown)).Select
rng.RemoveDuplicates Columns:=(1), Header:=xlGuess
Next
End Sub
`
My error seems to be in defining the range correctly. Each sheet will have a different number of entries to remove duplicates from. Sheet1 might have 50 rows and reduce to 6. Sheet2 could have 70 and reduce to 3. Sheet3 could have 20 rows and reduce to 12 uniques. Excel does not let you remove duplicates from range (B:B!)
How can I properly define my range so I can remove duplicates in a loop for a dynamically defined range for each sheet(sheet=tabs in workbook)?
EDIT 2-23-17
New code from Y0wE3K
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets
ws.Columns("P:P").RemoveDuplicates,Columns:=1, Header:=xlYes
Next
End Sub
Still does not work. If I manually select Column P before I run the macro, it works. But it only goes for the one sheet I have selected, it does not seem to execute the loop. Definitely does not automatically do each sheet, or prompt me for each one.
EDIT: 3/4
Make sure that you do not have any protected data, I also experienced issues with pivot tables but I think this may be permissions thank you for help.
Your RemoveStuff subroutine can be rewritten as:
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets ' Use Worksheets instead of Sheets,
' in case there are any Charts
'You can just select the whole column, rather than selecting
'specific rows
ws.Columns("B:B").RemoveDuplicates Columns:=1, Header:=xlGuess
Next
End Sub
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets
ws.Columns("P:P").RemoveDuplicates,Columns:=1, Header:=xlYes
Next
End Sub
This code will work. As a final note, please make sure you have no Protected Data, or pivot tables inside of the sheets you need to run the remove script on. For whatever reason that caused mine to fail, but running my script on the correct sheets that are unprotected worked GREAT.

How do I automate copying data from one worksheet in Excel and append it to an existing table in another worksheet?

I have two sheets of data. The first sheet is imported data that will show total users to my site from the day before. The second sheet is a table with all historical data from those daily reports. I'd like to automate a way to copy the data from my first sheet (that data will always be in the same cell) to a new row at the bottom of my existing table. Here's what I have:
Sub Insert_New_Rows()
Dim Lr As Integer
Lr = Range("AF" & Rows.Count).End(xlUp).Row
Rows(Lr + 1).Insert Shift:=xlDown
Cells(Lr + 1, "AF") = Cells(Lr, "AF") + 1
Sheets("Day Before").Range("$A$12:$B$12").Copy
Sheets("Historical").Cells(Lr + 1, "AF").Paste
Application.CutCopyMode = False
End Sub
In this, you'll see that my table is in columns AF and AG. When I run this macro, it only adds a row, it does not copy and paste the information.
I am not really sure where your table starts on the sheet "Day Before". So, I am assuming that it starts in row 1. Based on this assumption here is a little revision to your code:
Option Explicit
Sub Insert_New_Rows()
Dim lngNextEmptyRow As Long
Dim lngLastImportRow As Long
Dim shtYstrdy As Worksheet
Set shtYstrdy = ThisWorkbook.Worksheets("Day Before")
With ThisWorkbook.Worksheets("Historical")
lngNextEmptyRow = .Cells(.Rows.Count, "AF").End(xlUp).Row + 1
.Rows(lngNextEmptyRow).Insert Shift:=xlDown
.Cells(lngNextEmptyRow, "AF").Value2 = _
.Cells(lngNextEmptyRow - 1, "AF").Value2 + 1
lngLastImportRow = shtYstrdy.Cells(shtYstrdy.Rows.Count, "A").End(xlUp).Row
shtYstrdy.Range("A1:B" & lngLastImportRow).Copy _
Destination:=.Cells(lngNextEmptyRow, "AF")
End With
End Sub
Changes:
Explicit coding as suggested by #findwindow stating the workbook and the sheet before each Range, Cells, reference.
Copy and paste in one line of code (before three lines of code).
Using lngNextEmptyRow instead of LastRow so be can skip all these +1.
Determine the size (last row) of the table on the sheet "Day Before", so we know how much we need to copy over.
I hope this is the answer you've been looking for. Let me know if I misunderstood something or if anything requires more explanations.
There is no need to Active or Select Ranges. It is best to work with the Ranges directly. Rarely should you use ActiveCell, ActiveWorkSheet, or Selection.
This is how Copy and Paste work
Here is the shorthand for Copy and Paste
Range(SourceRange).Copy Range(DestinationRange)
Know that this will work for you:
Sheets("Day Before").Range("$A$12:$B$12").Copy Sheets("Historical").Cells(Rows.Count, "AF").End(xlUp).Offset(1)

Getting data validation list to populate a table

I have a Data Validation list in cell T3 in Sheet3 of my workbook. The list contains location names. In sheet1 of my workbook I have all the data for all locations in tables next to each other, e.g
location 1|date|score|percentage|target| |location 2|date|score|percentage|target| etc....
I am looking to select a location from the drop down list and that will copy in the relevant table to sheet3. So you just select a location and can see the data. I'm wondering if the best way to go about this is formulas or to use VBA (my experience with using drop down lists in VBA is limited). Here is something that I am currently working on but it is incomplete at the moment and still leads to the question of 'is there a faster way to do this in VBA'. Any help or advice is greatly appreciated! (my validation list is called List1)
=IF(ISNUMBER(A2),IF(ISERROR(VLOOKUP(A2,Sheet1!$A:$EG,MATCH(List1,Sheet1!$1:$1,0),FALSE)),0),"")
The idea is that i could have a table of formulas so depending on the list value, different data would appear.
This isn't complete but it should get you started / give you some ideas
Sub CopyTable()
Dim colNo, lastRow As Integer
Dim ws1, ws3 As Worksheet
Set ws1 = Sheets("Sheet1") ' assign the worksheet variables
Set ws3 = Sheets("Sheet3")
colNo = Application.Match(ws1.Range("T1"), ws1.Range("A1:R1")) ' work out which column the required table starts in
lastRow = ws1.Cells(10000, colNo).End(xlUp).Row ' work out the last row of the table
ws1.Range(ws1.Cells(1, colNo), ws1.Cells(lastRow, colNo + 4)).Copy ws3.Range("A1") ' copy the table
End Sub

Excel VBA: Output Distinct Values and Subtotals

I have data of this form:
Category Source Amount
Dues FTW $100
Donations ODP $20
Donations IOI $33
Dues MMK $124
There is no sort order. The categories are unknown at compile time. I want a VBA macro to cycle through the range, output a list of distinct values, with the subtotals for each. For the above data, it would look like this:
Category Total Amount
Dues $224
Donations $55
How can I do this? Also, is there a way to make the macro run every time the table above is updated, or is it necessary for the user to click a button?
You may want to use a built in Excel feature to do this. Looping can take a long time and be problematic if you have a lot of values to loop through.
Something like the following might get you started on creating a pivot table (from http://www.ozgrid.com/News/pivot-tables.htm)
Sub MakeTable()
Dim Pt As PivotTable
Dim strField As String
'Pass heading to a String variable
strField = Selection.Cells(1, 1).Text
'Name the list range
Range(Selection, Selection.End(xlDown)).Name = "Items"
'Create the Pivot Table based off our named list range.
'TableDestination:="" will force it onto a new sheet
ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, _
SourceData:="=Items").CreatePivotTable TableDestination:="", _
TableName:="ItemList"
'Set a Pivot Table variable to our new Pivot Table
Set Pt = ActiveSheet.PivotTables("ItemList")
'Place the Pivot Table to Start from A3 on the new sheet
ActiveSheet.PivotTableWizard TableDestination:=Cells(3, 1)
'Move the list heading to the Row Field
Pt.AddFields RowFields:=strField
'Move the list heading to the Data Field
Pt.PivotFields(strField).Orientation = xlDataField
End Sub
This is for subtotals (though I much prefer pivot tables)
http://msdn.microsoft.com/en-us/library/aa213577(office.11).aspx
EDIT:
I reread and have the following thoughts. Set up the pivot table on a separate sheet (without using any code) then put the following code on the sheet that has the pivot table so that the table will update everytime the sheet is selected.
Private Sub Worksheet_Activate()
Dim pt As PivotTable
'change "MiPivot" to the name of your pivot table
Set pt = ActiveSheet.PivotTables("MyPivot")
pt.RefreshTable
End Sub
Edit #2
Refresh all pivot tables on sheet
http://www.ozgrid.com/VBA/pivot-table-refresh.htm
Private Sub Worksheet_Activate()
Dim pt As PivotTable
For Each pt In ActiveSheet.PivotTables
pt.RefreshTable
Next pt
End Sub
The link has multiple options on how to refresh pivot tables in the sheet/workbook.