Copy data to another spreadsheet based off value stored in string - excel

I have the below code for one of my financial reports and I'm struggling with updating the code to make it more automated. The code creates a string of the column headers stored in multiple sheets. Each column header is a new tab in wb2. I can't figure out how to get formulas copied into a new address range. it needs to copy the values to that Sheet in wb2 and then move on to the next.
So the code needs to:
1/put the column headers to a string/array [Works]
2/look through string/array and find that column in wb1 [Works]
3/then copy specific ranges to wb2 (name is based of column header/string value) [Works]
4/copy formula into column G, based on row similar to what it does for column A addresses - for example if the range is G9, it needs to copy the formula H9-A9, etc
5/go to next value
Any help or direction would be appreciated.
Sub Prepare_CYTD_Report()
Dim addresses() As String
Dim addresses2() As String
Dim wb1 As Workbook, wb2 As Workbook
Dim my_Filename
'Declare variables for MHP60
Dim i As Long, lastcol As Long
Dim tabNames As Range, cell As Range, tabName As String
'Declare variables for MHP61
Dim i2 As Long, lastCol2 As Long
Dim tabNames2 As Range, cell2 As Range, tabName2 As String
'Declare variables for MHP62
Dim i3 As Long, lastCol3 As Long
Dim tabNames3 As Range, cell3 As Range, tabName3 As String
addresses = Strings.Split("A9,A12:A26,A32:A38,A42:A58,A62:A70,A73:A76,A83:A90", ",") 'Trial Balance string values
addresses2 = Strings.Split("G9,G12:G26,G32:G38,G42:G58,G62:G70,G73:G76,G83:G90", ",") 'Prior Month string values
Set wb1 = ActiveWorkbook 'Trial Balance to Financial Statements Workbook
'*****************************Load Column Header Strings
lastcol = wb1.Sheets("MHP60").Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames = wb1.Sheets("MHP60").Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP60", vbCritical
Exit Sub
End If
lastCol2 = wb1.Sheets("MHP61").Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames2 = wb1.Sheets("MHP61").Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP61", vbCritical
Exit Sub
End If
lastCol3 = wb1.Sheets("MHP62").Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames3 = wb1.Sheets("MHP62").Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP62", vbCritical
Exit Sub
End If
'*****************************Open CYTD/FYTD files
my_Filename = Application.GetOpenFilename(fileFilter:="Excel Files,*.xl*;*.xm*", Title:="Select File to create Reports")
If my_Filename = False Then
Exit Sub
End If
Application.ScreenUpdating = False
Set wb2 = Workbooks.Open(my_Filename)
'*****************************Copy values to Financial statements workbook
For Each cell In tabNames
tabName = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets("MHP60").Evaluate("ISREF('[" & wb2.Name & "]" & tabName & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName).Range(addresses(i)).Value2 = wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'wb2.Sheets(tabName).Range(addresses2(i)).Value2 =
'Debug.Print "data for " & wb2.Sheets(tabName).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName & " was not found in " & wb2.Name
End If
Next cell
For Each cell In tabNames2
tabName2 = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets("MHP61").Evaluate("ISREF('[" & wb2.Name & "]" & tabName2 & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName2).Range(addresses(i)).Value2 = wb1.Sheets("MHP61").Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName2).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP61").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName2 & " was not found in " & wb2.Name
End If
Next cell
For Each cell In tabNames3
tabName3 = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets("MHP62").Evaluate("ISREF('[" & wb2.Name & "]" & tabName3 & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName3).Range(addresses(i)).Value2 = wb1.Sheets("MHP62").Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName2).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP62").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName3 & " was not found in " & wb2.Name
End If
Next cell
Application.ScreenUpdating = True
End Sub

Sub Prepare_CYTD_Report()
Dim addresses() As String
Dim wb1 As Workbook, wb2 As Workbook
Dim i As Long, lastCol As Long, my_FileName
Dim tabNames As Range, cell As Range, tabName As String
addresses = Strings.Split("A12:A26,A32:A38,A42:A58,A62:A70,A73:A76,A83:A90", ",")
Set wb1 = ActiveWorkbook 'Trial Balance to Financial Statements
lastCol = wb1.Sheets("MHP60").Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames = wb1.Sheets("MHP60").Cells(4, 3).Resize(1, lastCol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP60", vbCritical
Exit Sub
End If
'*****************************Open CYTD/FYTD files
my_FileName = Application.GetOpenFilename(FileFilter:="Excel Files,*.xl*;*.xm*")
If my_FileName = False Then
Exit Sub
End If
Application.ScreenUpdating = False
Set wb2 = Workbooks.Open(my_FileName)
For Each cell In tabNames
tabName = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb2.Worksheets(1).Evaluate("ISREF('" & tabName & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName).Range(addresses(i)).Value2 = wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName & " was not found in " & wb2.Name
End If
Next cell
Application.ScreenUpdating = True
End Sub
In view of the observation made in my comment, the code presented above assumes that
the actual cell values on row 4 of MHP60 are the values 'as is' of
the actual tab names
those cell values were manually entered, i.e. not formula-driven

Related

Add another filter criteria

How do I add another filter criteria?
So that I can filter by date (like it does) and if comboBox1 value = to what is in column A for each row
The other one I have is filter by date (like it does) and if there is a value in column H for each row
Private Sub CommandButton1_Click()
Dim strStart As String, strEnd As String, strPromptMessage As String
If TextBox1.Value = "" Then
TextBox1.Value = Date
End If
If TextBox2.Value = "" Then
TextBox2.Value = Date
End If
'Prompt the user to input the start date
strStart = TextBox1.Value
'Validate the input string
If Not IsDate(strStart) Then
strPromptMessage = "Oops! It looks like your entry is not a valid " & _
"date. Please retry with a valid date..."
MsgBox strPromptMessage
Exit Sub
End If
'Prompt the user to input the end date
strEnd = TextBox2.Value
'Validate the input string
If Not IsDate(strStart) Then
strPromptMessage = "Oops! It looks like your entry is not a valid " & _
"date. Please retry with a valid date..."
MsgBox strPromptMessage
Exit Sub
End If
'Call the next subroutine, which will do produce the output workbook
Call CreateSubsetWorksheet(strStart, strEnd)
Unload Me
End Sub
Public Sub CreateSubsetWorksheet(StartDate As String, EndDate As String)
Dim wksData As Worksheet, wksTarget As Worksheet
Dim lngLastRow As Long, lngLastCol As Long, lngDateCol As Long
Dim rngFull As Range, rngResult As Range, rngTarget As Range
'Set references up-front
Set wksData = ThisWorkbook.Worksheets("CopyDatabase")
lngDateCol = 5 '<~ we know dates are in column E
'Identify the full data range on Sheet1 (our data sheet) by finding
'the last row and last column
lngLastRow = LastOccupiedRowNum(wksData) '<~ straight from VBA Toolbelt!
'lngLastRow = Cells(Rows.Count, 1).End(xlUp).Row
lngLastCol = LastOccupiedColNum(wksData) '<~ straight from VBA Toolbelt!
'lngLastCol = Cells(1, Columns.Count).End(xlToLeft).Column
With wksData
Set rngFull = .Range(.Cells(3, 1), .Cells(lngLastRow, lngLastCol))
End With
'Apply a filter to the full range we just assigned to get rows
'that are in-between the start and end dates
With rngFull
.AutoFilter Field:=lngDateCol, _
Criteria1:=">=" & StartDate, _
Criteria2:="<=" & EndDate
'If the resulting range contains only 1 row, that means we filtered
'everything out! Check for this situation, catch it and exit
If wksData.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count = 1 Then
MsgBox "Oops! Those dates filter out all data!"
'Clear the autofilter safely and exit sub
wksData.AutoFilterMode = False
If wksData.FilterMode = True Then
wksData.ShowAllData
End If
Exit Sub
Else '<~ otherwise we're all good!
'Assign ONLY the visible cells, which are in the
'date range specified
Set rngResult = .SpecialCells(xlCellTypeVisible)
'clear contents
ThisWorkbook.Sheets("Reports").Range("A3:A" & Range("A3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("B3:B" & Range("B3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("C3:C" & Range("C3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("D3:D" & Range("D3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("E3:E" & Range("E3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("F3:F" & Range("F3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("G3:G" & Range("G3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("H3:H" & Range("H3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("I3:I" & Range("I3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("J3:J" & Range("J3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("K3:K" & Range("K3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("L3:L" & Range("L3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("M3:M" & Range("M3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("N3:N" & Range("N3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("O3:O" & Range("O3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("P3:P" & Range("P3").End(xlDown).Row).ClearContents
ThisWorkbook.Sheets("Reports").Range("Q3:Q" & Range("Q3").End(xlDown).Row).ClearContents
'Create a new Worksheet to copy our data to and set up
'a target Range (for super easy copy / paste)
Set wksTarget = ThisWorkbook.Sheets("Reports")
Set rngTarget = wksTarget.Cells(2, 1)
rngResult.Copy Destination:=rngTarget
End If
End With
'Clear the autofilter safely
wksData.AutoFilterMode = False
If wksData.FilterMode = True Then
wksData.ShowAllData
End If
'Holler at the user, our macro is done!
MsgBox "Data transferred!"
End Sub

Delete multiple array ranges giving runtime 1004 error

I am trying to setup a macro to read a string of tab names (ProductTabs) and then search the workbook. Once the ProductTabs = the workbook tab name, it will clear the contents from 2 different ranges. I had it all manually coded, but its possible that additional tabs may be added. I'm stuck with getting the look to work correctly. I get a runtime 1004 - Application defined or object defined error, when it hits this line of code: Set ProductTabs = wb1.Sheets("tabNames").Cells(3, 2).Resize(1, lastcol - 1).SpecialCells(xlCellTypeConstants)
Sub ResetBudget()
Dim wb1 As Workbook
Dim addresses() As String
Dim addresses2() As String
Dim ProductTabs As Range, cell As Range
Dim i As Long, lastcol As Long
addresses = Strings.Split("B9,B12:B26,B32:B38,B42:B58,B62:B70,B73:B76,B83:B90", ",")
addresses2 = Strings.Split("I9,I12:I26,I32:I38,I42:I58,I62:I70,I73:I76,I83:I90", ",")
lastcol = wb1.Sheets("tabNames").Cells(3, Columns.Count).End(xlToLeft).Column
Set wb1 = ThisWorkbook
Set ProductTabs = wb1.Sheets("tabNames").Cells(3, 2).Resize(1, lastcol - 1).SpecialCells(xlCellTypeConstants)
For Each cell In ProductTabs
If CStr(wb1.Sheets("tabNames").Evaluate("ISREF('[" & wb1.Name & "]" & ProductTabs & "'!$A$1)")) = "True" Then
For i = 0 To UBound(addresses)
wb1.Sheets(ProductTabs).Range(addresses(i)).ClearContents
Next i
'wb1.Sheets("1061 ABAD-F").Range("B9,B12:B26,B32:B38,B42:B58,B62:B70,B73:B76,B83:B90").ClearContents
'wb1.Sheets("1061 ABAD-F").Range("I9,I12:I26,I32:I38,I42:I58,I62:I70,I73:I76,I83:I90").ClearContents
'wb1.Sheets("1062 TANF-F").Range("B9,B12:B26,B32:B38,B42:B58,B62:B70,B73:B76,B83:B90").ClearContents
'wb1.Sheets("1062 TANF-F").Range("I9,I12:I26,I32:I38,I42:I58,I62:I70,I73:I76,I83:I90").ClearContents
'wb1.Sheets("1063 Duals-F").Range("B9,B12:B26,B32:B38,B42:B58,B62:B70,B73:B76,B83:B90").ClearContents
'wb1.Sheets("1063 Duals-F").Range("I9,I12:I26,I32:I38,I42:I58,I62:I70,I73:I76,I83:I90").ClearContents
'wb1.Sheets("1064 CSHCS-F").Range("B9,B12:B26,B32:B38,B42:B58,B62:B70,B73:B76,B83:B90").ClearContents
'wb1.Sheets("1064 CSHCS-F").Range("I9,I12:I26,I32:I38,I42:I58,I62:I70,I73:I76,I83:I90").ClearContents
Else
Debug.Print "A tab " & ProductTabs & " was not found in " & wb1.Name
End If
Next cell
End Sub

Inserting value in 2nd cell based on value in 1st cell

I am trying to write a script where as it reads down an entire column starting with E2 and if a cell in that column has a particular value (for this example, let's say A, E, I, O, or U) then it enters a value of "Y" in cell F2, however it continues this pattern until it runs out of filled cells in column E.
I understand the logic of
Dim ColE As String
For ColE = 2 To Rows.Count
Next i
If E1 = "A" Or "E" Or "I" Or "O" Or "U" Then F2 = "Y"
but how do i repeat that say all the way down the entire column of E until it runs out of filled cells in column E
Here is an easy way to implement a list of OR's:
Sub marine()
Dim s1 As String, s2 As String
s1 = "AEIOU"
For i = 2 To 25
If Range("E" & i).Value <> "" Then
If InStr(s1, Range("E" & i).Value) > 0 Then
Range("F" & i).Value = "Y"
End If
End If
Next i
End Sub
Suitable option here is using the select case command with an if-loop
for i = 2 to Cells(Rows.Count, 5).End(xlUp).Row '5 = Column E
Select Case Range("E"&i).value
Case "A", "E", "I", "O", "U"
Range("F"&i).value
End Select
next
Using Select Case allows you to also give different commands for other inputs in column E and is way easier to handle than if-conditions for your specific requirements.
Cells(Rows.Count, 5).End(xlUp).Row '5
This will return the row number of the last entry in the fifth column (column E). You can use it in the for-loop to iterate until the very last row.
Search Multiple Criteria
Copy the code into a standard module (e.g. Module1).
Carefully adjust the values in the constants section.
The Code
Option Explicit
Sub searchMultipleCriteria()
' Handle Errors
Const Proc = "searchMultipleCriteria"
On Error GoTo cleanError
' Define constants.
Const SheetName As String = "Sheet1"
Const FirstRow As Long = 2
Const CriteriaCol As Variant = "E" ' 1 or "A"
Dim CriteriaVals As Variant: CriteriaVals = Array("A", "E", "I", "O", "U")
Const ResultCol As Variant = "F" ' 1 or "A"
Const ResultVal As String = "Y"
Dim wb As Workbook: Set wb = ThisWorkbook
' Write values from Criteria Column Range to Criteria Array.
Dim ws As Worksheet: Set ws = wb.Worksheets(SheetName)
Dim rng As Range
Set rng = ws.Columns(CriteriaCol).Find("*", , xlFormulas, , , xlPrevious)
If rng Is Nothing Then GoTo EmptyColumn
If rng.Row < FirstRow Then GoTo NoRange
Set rng = ws.Range(ws.Cells(FirstRow, CriteriaCol), rng)
Dim Criteria As Variant: Criteria = rng.Value
' Write values from Result Column Range to Result Array.
Set rng = rng.Offset(, ws.Columns(ResultCol).Column - rng.Column)
Dim Result As Variant: Result = rng.Value
' Modify values in Result Array.
Dim i As Long, Curr As Variant
For i = 1 To UBound(Criteria)
' Note: 'Match' is not case-sensitive i.e. A=a...
Curr = Application.Match(Criteria(i, 1), CriteriaVals, 0)
If Not IsError(Curr) Then
Result(i, 1) = ResultVal
Else ' Maybe you wanna do something here...
'Result(i, 1) = "N"
End If
Next i
' Write values from Result Array to Result Range.
rng.Value = Result
' Inform user.
MsgBox "Data transferred.", vbInformation, "Success"
' Revert Settings (not utilized in this Sub)
CleanExit:
Exit Sub
' Not As Planned
EmptyColumn:
MsgBox "Looking in an empty column to define a range with values!?", _
vbExclamation, "'" & Proc & "': Empty Column"
GoTo CleanExit
NoRange:
MsgBox "Trying to define a range with an ending row lower than " _
& "the starting row!?", _
vbExclamation, "'" & Proc & "': No Range"
GoTo CleanExit
cleanError:
MsgBox "An unexpected error occurred in '" & Proc & "'!" & vbCr _
& "Run-time error '" & Err.Number & "':" & vbCr & Err.Description, _
vbCritical, "'" & Proc & "': Unexpected Error"
On Error GoTo 0
GoTo CleanExit
End Sub

Convert pivot table to sumif function - Error 424 - Excel VBA

I would like to convert a Pivot Table to a sum if statement using a VBA macro.
I found one which used to work on Excel 2016 (https://www.excelcampus.com/vba/convert-pivot-table-to-sumifs-formulas-vba-macro/) since I went to 0365, the macro is not working.
I tried to fix the code myself but got stuck on the line
Set rSource = Application.Evaluate(Application.ConvertFormula(PivotTable.SourceData, xlR1C1, xlA1))
which led to a #424 error object needed.
Any ideas would be gratefully accepted!
The whole code is the following`and the error seems to come from the function part:
Option Explicit
Dim pvt As PivotTable
Dim rSource As Range
Dim wsSource As Worksheet
Dim bTable As Boolean
Dim pi As PivotItem
Dim pc As PivotCell
Dim pf As PivotField
Dim wsNew As Worksheet
Dim wsPivot As Worksheet
Dim c As Range
Dim lFunction As Long
Dim sSumRange As String
Dim sCritRange As String
Dim sCriteria As String
Dim sFormula As String
Dim sFormulaPage As String
Dim sSearchField As String
Dim sDataSheet As String
Dim lDataRows As Long
Dim sPageRange As String
Dim lCol As Long
Dim bArray As Boolean
Dim sTableName As String
Dim sFormulaArgs As String
Dim sFormulaCnt As String
Dim lLblRow As Long
Dim lLblCol As Long
Dim sFilter As String
Dim sDataField As String
Dim bReturn As Boolean
Sub Convert_Pivot_to_Formulas()
'---------------------------------------------------------------------------------------
' Procedure : Convert_Pivot_to_Formulas
' Author : Jon Acampora, Excel Campus LLC, www.excelcampus.com
' Date : 10/13/2014
' Purpose : Creates a copy of the selected pivot table on a new sheet and converts
' all cells in the values area to SUMIFS, COUNTIFS, or AVERAGEIFS formulas
' Details : The following is a list of features, requirement, and limitations of the macro.
' Features
' - Works with page fields with multiple items in filter of one page field.
' Creates the page field criteria across columns and creates array formulas.
' Requirements
' - Fields in the pivot containing dates must be in the same format as the source data.
' - Source data must be in same workbook. This can be expaned to ref source data in other workbooks.
' Limitations
' - Does not work with grouped date fields. The criteria ranges do NOT exist in the source data.
' Create the date group fields as columns in the source data to solve this issue.
'---------------------------------------------------------------------------------------
'Set pivot table variables
On Error Resume Next
Set pvt = ActiveCell.PivotTable
Set wsPivot = ActiveSheet
On Error GoTo 0
If pvt Is Nothing Then
MsgBox "Please select a Pivot Table first.", vbOKOnly, "Convert Pivot to Formula Error"
Exit Sub
End If
'Check if source data is in the same workbook.
If Get_Pivot_Source Then
On Error GoTo Err_Handle
'-------------------------------------------------------
'1. Create new sheet with shell of pivot table - filter, rows, columns areas
'-------------------------------------------------------
Set wsNew = Worksheets.Add(after:=ActiveSheet)
sDataSheet = wsSource.Name
lDataRows = rSource.Rows.Count
If bTable Then sTableName = pvt.SourceData
'Copy pivot table values to new sheet
wsPivot.Select
wsPivot.Range(pvt.TableRange1.Address).Copy
With wsNew.Range(pvt.TableRange1.Address)
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
.PasteSpecial Paste:=xlPasteColumnWidths
End With
If pvt.PageFields.Count > 0 Then
wsPivot.Range(pvt.PageRange.Address).Copy
With wsNew.Range(pvt.PageRange.Address)
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
.PasteSpecial Paste:=xlPasteColumnWidths
End With
End If
'-------------------------------------------------------
'2. Add page field filters across columns in new sheet
'-------------------------------------------------------
If pvt.PageFields.Count > 0 Then
For Each pf In pvt.PageFields
sPageRange = pf.LabelRange.Offset(, 1).Resize(1, 1).Address
sFilter = pf.LabelRange.Offset(, 1).Resize(1, 1).Value
lCol = 0 'offset 1 col to the right
Select Case sFilter
Case "(All)"
'skip
Case "(Multiple Items)"
'Loop pivot items and add selected items to page range across columns
For Each pi In pf.PivotItems
If pi.Visible Then
wsNew.Range(sPageRange).Offset(, lCol).Resize(1, 1).Value = pi.Name
lCol = lCol + 1
End If
Next pi
Case Else 'One item selected
lCol = 1
wsPivot.Range(sPageRange).Offset(, lCol).Resize(1, 1).Value = wsNew.Range(sPageRange).Offset(, lCol).Resize(1, 1).Value
End Select
'Create string for formula
If lCol > 0 Then 'filters exist
If bTable Then
sCritRange = sTableName & "[" & pf.Name & "]"
Else
sSearchField = pf.Name
sCritRange = "'" & sDataSheet & "'!" & rSource.Resize(1).Find(What:=sSearchField, LookAt:=xlWhole).Offset(1).Resize(lDataRows - 1, 1).Address
End If
sCriteria = wsNew.Range(sPageRange).Resize(1, lCol).Address
sFormulaPage = sFormulaPage & "," & sCritRange
sFormulaPage = sFormulaPage & "," & sCriteria
End If
'IFS formula will have to be an array if there are multiple critera (range) in criteria argument
If lCol > 1 Then bArray = True
Next pf
End If
'-------------------------------------------------------
'3. Loop through each cell in values area to build formula.
'-------------------------------------------------------
For Each c In pvt.DataBodyRange.Cells
Set pc = c.PivotCell
sFormula = ""
sFormulaArgs = ""
'-------------------------------------------------------
'4. Create SUM RANGE reference for formula
'-------------------------------------------------------
'Check if function is sum, count, or average
If pc.PivotField.Function = xlSum Or pc.PivotField.Function = xlCount Or pc.PivotField.Function = xlAverage Then
'Count the criteria, if 0 then it's a total and no IFS needed
sCriteria = ""
'Add column items to filter array
If pc.PivotCellType = xlPivotCellValue Then
sDataField = pc.PivotField.SourceName
lFunction = pc.PivotField.Function
'Add Sum Range
lFunction = pc.PivotField.Function
If bTable Then
sSumRange = sTableName & "[" & pc.PivotField.SourceName & "]"
Else
sSearchField = pc.PivotField.SourceName
sSumRange = "'" & sDataSheet & "'!" & rSource.Resize(1).Find(What:=sSearchField, LookAt:=xlWhole).Offset(1).Resize(lDataRows - 1, 1).Address
End If
'-------------------------------------------------------
'5. Loop through ROW items of pivotcell and add row refs to formula
'-------------------------------------------------------
If pc.RowItems.Count Then
For Each pi In pc.RowItems
If bTable Then
sCritRange = sTableName & "[" & pi.Parent.Name & "]"
Else
sSearchField = pi.Parent.Name
sCritRange = "'" & sDataSheet & "'!" & rSource.Resize(1).Find(What:=sSearchField, LookAt:=xlWhole).Offset(1).Resize(lDataRows - 1, 1).Address
End If
'Find the address of the pivotcells labelrange for the criteria address
'Start from the current row and loop up through the label range until the
'pivotitem name is found. Required due to variety of pivot table layouts.
lLblCol = pi.LabelRange.Column
For lLblRow = c.Row To pi.Parent.LabelRange.Row + 1 Step -1
If Cells(lLblRow, lLblCol).Value = pi.Name Then
sCriteria = Cells(lLblRow, pi.LabelRange.Column).Address
Exit For
End If
Next lLblRow
If sCriteria <> "" Then
sFormulaArgs = sFormulaArgs & "," & sCritRange
sFormulaArgs = sFormulaArgs & "," & sCriteria
End If
sCriteria = ""
Next pi
End If
'-------------------------------------------------------
'6. Loop through COLUMN items of pivotcell and add row refs to formula
'-------------------------------------------------------
If pc.ColumnItems.Count Then
For Each pi In pc.ColumnItems
If bTable Then
sCritRange = sTableName & "[" & pi.Parent.Name & "]"
Else
sSearchField = pi.Parent.Name
sCritRange = "'" & sDataSheet & "'!" & rSource.Resize(1).Find(What:=sSearchField, LookAt:=xlWhole).Offset(1).Resize(lDataRows - 1, 1).Address
' If sCritRange Is Nothing Then
' On Error GoTo 0
' Else
' End If
End If
'Find the address of the pivotcells labelrange for the criteria address
'Start from the current column and loop back left through the label range until the
'pivotitem name is found. Required due to variety of pivot table layouts.
lLblRow = pi.LabelRange.Row
For lLblCol = c.Column To pi.LabelRange.Column Step -1
If Cells(lLblRow, lLblCol).Value = pi.Name Then
sCriteria = Cells(pi.LabelRange.Row, lLblCol).Address
Exit For
End If
Next lLblCol
If sCriteria <> "" Then
sFormulaArgs = sFormulaArgs & "," & sCritRange
sFormulaArgs = sFormulaArgs & "," & sCriteria
End If
sCriteria = ""
Next pi
End If
'-------------------------------------------------------
'7. Build Formula based on function type of pivotcell
'-------------------------------------------------------
Select Case pc.PivotField.Function
Case xlSum
If sFormulaArgs = "" And sFormulaPage = "" Then 'Don't need IFS when there are no criteria (total rows/columns)
sFormula = "=SUM(" & sSumRange & ")"
Else
If bArray Then
sFormula = "=SUM(SUMIFS(" & sSumRange & sFormulaPage & sFormulaArgs & "))"
Else
sFormula = "=SUMIFS(" & sSumRange & sFormulaPage & sFormulaArgs & ")"
End If
End If
Case xlCount
If sFormulaArgs = "" And sFormulaPage = "" Then 'Don't need IFS when there are no criteria (total rows/columns)
sFormula = "=COUNT(" & sSumRange & ")"
Else
sFormulaCnt = sFormulaPage & sFormulaArgs 'Don't need sum range for countifs
sFormulaCnt = Right(sFormulaCnt, Len(sFormulaCnt) - 1) 'trim preceding comma
If bArray Then
sFormula = "=SUM(COUNTIFS(" & sFormulaCnt & "))"
Else
sFormula = "=COUNTIFS(" & sFormulaCnt & ")"
End If
End If
Case xlAverage
If sFormulaArgs = "" And sFormulaPage = "" Then 'Don't need IFS when there are no criteria (total rows/columns)
sFormula = "=AVERAGE(" & sSumRange & ")"
Else
sFormula = "=AVERAGEIFS(" & sSumRange & sFormulaPage & sFormulaArgs & ")" 'AVERAGEIFS not working with array formula, returns errors
End If
End Select
'-------------------------------------------------------
'8. Add formula to new sheet
'-------------------------------------------------------
If bArray Then
If Len(sFormula) < 255 Then
wsNew.Range(c.Address).FormulaArray = sFormula
Else
'.FormulaArray hits an error if formula string is > 255 characters
'Add error handling here
End If
Else
wsNew.Range(c.Address).Formula = sFormula
End If
End If
End If
Next c
End If
wsNew.Select
Exit Sub
Err_Handle:
MsgBox Err.Description & vbNewLine & "Current Cell: " & c.Address, _
vbCritical, "Convert Pivot to Formulas Error"
End Sub
Function Get_Pivot_Source() As Boolean
'Determine if source is a cell reference, named range, or Excel Table
'Set source range variables
'Consider using the PivotCache.SourceType property to check this.
'http://msdn.microsoft.com/en-us/library/office/ff194557.aspx
'On Error GoTo Err_Handler
'Set variables for selected pivot table
bReturn = False
Set rSource = Nothing
Set wsSource = Nothing
Set pvt = ActiveCell.PivotTable
Set wsPivot = ActiveSheet
bTable = False
If ActiveCell.PivotTable.PivotCache.SourceType = xlDatabase Then
If InStr(ActiveCell.PivotTable.SourceData, "[") = 0 Then 'check if source data contains workbook name - bypass external source range - Temp TO DO
If InStr(ActiveCell.PivotTable.SourceData, ":") > 0 Then 'if data source range is a cell ref range
Set rSource = Application.Evaluate(Application.ConvertFormula(ActiveCell.PivotTable.SourceData, fromReferenceStyle:=xlR1C1, toReferenceStyle:=xlA1))
Else 'if Table or Named Range are used as data source range
Set rSource = Range(pvt.SourceData)
On Error GoTo SkipTable 'check if the data source name is a table
Set rSource = Range(pvt.SourceData & "[#All]")
bTable = True
SkipTable:
On Error GoTo 0
End If
Set wsSource = rSource.Parent
bReturn = True
End If
End If
Get_Pivot_Source = bReturn
Exit Function
Err_Handler:
MsgBox "Error in Get_Source_Range procedure."
Get_Pivot_Source = False
End Function

Excel 2010 VBA scripting

I’m a complete newbie with VBA but have managed to cobble together the following which works fine for my worksheet where I have assigned the code to a command button. My problem is that my worksheet has in excess of 3000 rows and I don’t really want to create 3000 buttons.
My current thinking would be to have a script search a range of cells for a specific condition (i.e. TRUE) then run my original code as a subscript for each cell that matches the condition. I have tried creating a loop to match the condition being searched but don't know how to set the result(s) as an active cell.
Could anyone give me some pointer on how to achieve this or propose a better solution?
Thanks.
Sub Send_FWU_to_E_Drive()
Dim aTemp As String
Dim bTemp As String
Dim cTemp As String
Dim dTemp As String
Dim eTemp As String
Dim subdir As String
aTemp = "c:\test\"
bTemp = "E:\romdata\"
cTemp = ActiveCell.Offset(, -5) & ".fwu"
dTemp = ActiveWorkbook.path
eTemp = "\Firmware files"
subdir = "\Firmware Files\" & ActiveCell.Offset(, -5) & "\" & ActiveCell.Offset(, -5) & ".fwu"
MsgBox "The path of the active workbook is " & dTemp & subdir
If Dir(dTemp & subdir) = "" Then
MsgBox "Please check the file and ensure it is suitable for firmware updating with an SD card."
Exit Sub
End If
MsgBox "The file " & cTemp & " is being copied to " & bTemp
If Dir("e:\romdata", vbDirectory) = "" Then MkDir "E:\romdata"
If Dir(bTemp & "nul") = "" Then
MsgBox "The Destination Directory is missing, please ensure your SD Card is formatted, mapped as drive E and has a romdata directory."
Exit Sub
End If
FileCopy dTemp & subdir, bTemp & cTemp
End Sub
First modify your function to accept a range argument, which we'll call cell:
Sub Send_FWU_to_E_Drive(cell as Excel.Range)
Then change all the ActiveCell references in that Sub to cell.
The sub below loops through each cell in column B of the Active sheet and, if it's TRUE, calls your routine with the cell in column A of that row. So your offsets in the code in Send_FWU_to_E_Drive are all relative to the cell in column A. This code is untested, but should be close:
Sub Test
Dim Cell as Excel.Range
Dim LastRow as Long
With ActiveSheet
LastRow = .Range("A" & .Rows.Count).End(xlup).Row
For Each Cell in .Range("B2:B" & LastRow) 'Search for TRUE in column B
If Cell.Value = TRUE Then
Send_FWU_to_E_Drive cell.Offset(0,-1) 'Column A Cell
End If
Next Cell
End With
End Sub
EDIT: Per #Siddharth's suggestion, here's a Find/FindNext version:
Sub Test()
Dim cell As Excel.Range
Dim LastRow As Long
Dim SearchRange As Excel.Range
Dim FirstFindAddress As String
With ActiveSheet
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set SearchRange = .Range("B2:B" & LastRow) 'Search for TRUE in column B
Set cell = SearchRange.Find(what:=True, after:=SearchRange.Cells(1))
If Not cell Is Nothing Then
FirstFindAddress = cell.Address
Send_FWU_to_E_Drive cell.Offset(0, -1)
Do
Send_FWU_to_E_Drive cell.Offset(0, -1)
Set cell = SearchRange.FindNext(after:=cell)
Loop While Not cell Is Nothing And cell.Address <> FirstFindAddress
End If
End With
End Sub

Resources