Pull data from multiple closed workbooks and sheets in excel - arrays

I want to pull data from multiple workbooks and worksheets that are closed.
I'm able to extract the data by using the below formula:
=INDEX('C:\Users\Shubham\Downloads\Ex_Files_Excel_Macros_and_VBA_for_Beginners\Ex_Files_Excel_Macros_and_VBA_for_Beginners\Exercise Files\[03_01 Undo.xlsx]Attendance'!C:C, 6)
but I want to provide the path in a cell using CONCATENATE function let's say in E5 so that value in E5 comes like below:
'C:\Users\Shubham\Downloads\Ex_Files_Excel_Macros_and_VBA_for_Beginners\Ex_Files_Excel_Macros_and_VBA_for_Beginners\Exercise Files\[03_01 Undo.xlsx]Attendance'!C:C
So I want to use the formula like:
= INDEX(E5, 6)
where E5 has the path and range defined but this doesn't take the value in E5 as table array.
I can't use the indirect formula since it doesn't work with closed workbooks. I have tried to understand the VBA code but doesn't work out.
I would really appreciate it if someone can help me out to resolve this issue since I have to extract data from multiple workbooks and multiple sheets and have to use dynamic reference to path and range.

I had the same problem, wanting to extract data from multiple workbooks with a volatile worksheet address. Indirect and Concatenate worked, but only when source files were open. There is no function which would work with closed files.
A macro was the solution, which I found here;
https://www.mrexcel.com/board/threads/vba-to-pull-data-from-dynamically-named-closed-workbooks.984156/
My solution uses a list of the source file name components with a volatile date component (date is the only variable in the source file names) and a volatile worksheet component (I need to take data for a person, where each person's name is the name of a worksheet in each file).
That list looks like this;List of File Names
I and K (Name) are volatile. These are modified in my list by having these cells reference separate input cells to simplify a query. Enter the name and the latest payroll date you want to query. It looks back a set number of cycles.
The formula to get the data I want is =COUNTIF(INDIRECT(CONCATENATE(H4,I4,J4,K4,L4)),"S")
How many times does S appear in range D63:U63 in tab Moe for each file.
The macro solution uses the Date information in column I to open all the source files as follows (I have added comments to hopefully make it clearer what each step does);
Public Sub Macro_Name()
' Opens Timesheets files to allow "Indirect" formula to obtain data
Dim r As Long
' I don't know what this does, but it is necessary
Application.ScreenUpdating = False
' Stops screen updating to speed up operation
Calculate
' Calculates to clear any previous data in the file. File is set to manual calculation.
With ThisWorkbook.ActiveSheet
For r = 4 To .Cells(Rows.Count, "I").End(xlUp).Row
' Starting at row 4, uses data in column I in the command below until the end of the data. You can't have any other data in column I.
Workbooks.Open Filename:="S:\Payroll\Weekly Timesheets " & .Cells(r, "I") & ".xlsm"
' Opens each file called Weekly Timesheets [date].xlsm
Next
Windows("[The name of your working file].xlsm").Activate
Calculate
Range("B2").Select
' This calculates your working file and goes to a convenient "home" cell
End With
Dim wb As Workbook
For Each wb In Application.Workbooks
If Not wb Is ThisWorkbook Then
wb.Close SaveChanges:=False
End If
Next
' This sub routine closes all open Excel files EXCEPT your working file. Best not to have other files open as it is set NOT to save.
Application.ScreenUpdating = True
End Sub
I found this page to set the file for manual calculation, which I preferred.
https://excel.tips.net/T001988_Forcing_Manual_Calculation_For_a_Workbook.html
I'm not sure if this solution is efficient, and it is not perhaps as elegant as I would like, but it has worked for me. I hope it helps.
Big shoutout to John_w at MrExcel.com who provided the core code above. I just fiddled a few things so it worked for me.

Related

Why does my attempt at referring to named ranges with a variant variable to which I (for-next)-store the names of ranges fail?

Apologies for the confusing title. I have multiple named ranges and I am trying to create a macro that would allow me to copy a certain row of each one of the ranges and paste it to however many following rows in each range as the user pleases. I will create 20 different macros depending on from which row the user would like to copy the selections, but for now I'm testing it with row 3.
The issue however is that I managed to store the name of the first range in a variant variable. However I have only succeeded in selecting the row with application.goto-function, but have failed in trying to copy certain rows of it. For example when I try to use the Range.(aspect(the name of my variable))-function I receive an error method 'range' of object '_Global' failed. I have also tried to create a new array based on the range that the name stored in the variable should bring but have failed in that too.
Public Sub copy_window_3()
Sheets("options").Select
ccArr = Range("ccAr").Value
copy_window rowstart:=3, copyquant:=Application.WorksheetFunction.Index(ccArr, rowstart)
Exit Sub
End Sub
Public Sub copy_window(rowstart As Double, copyquant As Variant)
Dim aspect As Variant
Dim copycounter As Integer
Dim aspcounter As Double
Dim ccArr() As Variant
Dim aspAr() As Variant
aspAr = Range("aspAr").Value
For aspcounter = 1 To UBound(aspAr, 1)
aspect = Application.WorksheetFunction.Index(aspAr, aspcounter)
Range(aspect).Rows(rowstart).Copy
For copycounter = 1 To copyquant
Range(aspect).Rows(rowstart + copyquant).PasteSpecial xlPasteValues
Next copycounter
Next aspcounter
End Sub
In case the code looks confusing: The macro first uses ccArr and rowstart variables to figure out from which row to start and how many rows to go. I intended to loop through each range name which are stored in aspAr and then copy the desired row and then loop and paste to each row that the user wishes.
Pardon me for the silly question, but I tried looking for the answer online for hours with no luck.
Thanks in advance for the help!
Cheers.

Excel VBA: Create Array from Filter Field Items?

A report I am creating in Excel involves several very similar pivot tables needing to be specifically filtered many times (i.e. a Year-to-Date table, a Quarter-to-Date table, etc, all needing to be filtered the exact same way before exported, then filtered again, then exported, etc)
So I looked into VBA as a way of accepting a few filter criteria, then filtering multiple tables that way, before looping.
However, I'm having a very tough time properly targeting PivotTables and specific fields, as it appears an integrated Value field is targeted and filtered via code differently than, say, a "filter' field I have attached to the top of the PivotTables, where they can accept no "begins with", "contains", etc, strings. They are just checkboxes, and one or multiple can be selected.
So it's one thing for me to tell it via VBA to select one item, and having it select all but one item. The latter requires the code to target every single possible value, but not the one that I want excluded.
My idea for this, then, is to create an array from every possible existing value in this filter field, then going through a loop where each value is added to my code as a value to check.
I have some code so far:
ActiveSheet.PivotTables("QTD_Pivot_By_Category").PivotFields( _
"[Range].[Address_1].[Address_1]").VisibleItemsList = Array( _
"[Range].[Address_1].&", "[Range].[Address_1].&[0]", "[Range].[Address_1].&[101]" _
, "[Range].[Address_1].&[INC]", "[Range].[Address_1].&[KRT]", _
"[Range].[Address_1].&[LTD]", "[Range].[Address_1].&[RPO]", _
"[Range].[Address_1].&[ INC]", "[Range].[Address_1].&[CORP]", _
"[Range].[Address_1].&[INC.]", "[Range].[Address_1].&[LTD.]", _
"[Range].[Address_1].&[LTEE]", "[Range].[Address_1].&[PAWS]", _
Now, if I just record this macro from actions in Excel, and do "select All", then de-select the one I don't want, it will error. It errors because it's selecting ~300 values, and while it's 'writing' this code, it errors when it hits the limit of "_" delimited breaks in one straight line of VBA code.
If my field is called "Address_1" as above, part of the range..."Range" (not sure where that's defined or why, but it works), can I get some help as to the most efficient way to define said ".VisibleItemList" as all POSSIBLE items in the list from a dynamic array rather than needing to be selected manually? This list will be different day-to-day so it can't just be a hardcoded flat list.
Ideally, also in a way that circumvents the max limit on "_" line breaks in a line of code in VBA for Excel.
If it's of any use for context, my table looks like this. See that checkbox drop-down? I want a snapshot of every updated value sitting in there to be put into an array and then iterated upon being added in a way similar to my example code:
Edit:
Since that filter field's values are being pulled from a local datasource, I decided to just grab those and make an array that way! So I'm starting my code this way:
Dim OGDataRange As Range, OGDataLastRow As Long
Dim ValueArray As Variant
OGDataLastRow = Worksheets("DATA QTD").Range("U2").End(xlDown).Row
Set OGDataRange = Worksheets("DATA QTD").Range("U2:U" & OGDataLastRow)
ValueArray = OGDataRange.Value
"ValueArray" is now my array. So I need help one-by-one pulling the values of this array, and adding them to my VisibleItemList as seen above.
Thank you so much for any assistance.
This might help you
Private Sub this()
Dim pf As PivotField
Dim pi As PivotItem
Dim strPVField As String
strPVField = "this"
Set pt = ActiveSheet.PivotTables("PivotTable1")
Set pf = pt.PivotFields(strPVField)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
On Error Resume Next
pf.AutoSort xlManual, pf.SourceName
For Each pi In pf.PivotItems
pi.Visible = False
Next pi
pf.AutoSort xlAscending, pf.SourceName
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
borrowed from
Deselect all items in a pivot table using vba

Text File to Array in Access VBA

I am looking to load a .txt file into a VBA array (in an access VBA), manipulate it there, and then paste the manipulated array into an access table. I will loop this macro then through round about 500 .txt files and populate the database with years of data.
I have done it before using Excel in this way:Populating the sheet for 1 .txt file, manipulating the data, loading into the database, clearing the sheet, and loading the next txt file and loop till all files have been processed. However, this takes years and it becomes obvious that Excel is not really needed, since everything is stored in Access anyway.
Since then, I have tried to figure out how to do it in access straight away, without using excel, but I have been struggling. I found some nice code on this board here:
Load csv file into a VBA array rather than Excel Sheet
and tried to amend it so it would work for me. Especially The_Barman's Answer at the bottom seems simple and very interesting.
I am new to arrays, VBA, SQL, basically everything, so maybe there is some big mistake I am making here that is easy to resolve. See my code below:
Sub LoadCSVtoArray()
Dim strfile As String
Dim strcon As String
Dim cn As ADODB.Connection
Dim rs As Recordset
Dim rsARR() As Variant
Set cn = New ADODB.Connection
strcon = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" & "\\filename.txt" &
";Extended Properties=""text;HDR=Yes;FMT=Delimited"";"
cn.Open strcon
strSQL = "SELECT * filename.txt;"
Set rs = cn.Execute(strSQL)
rsARR = WorksheetFunction.Transpose(rs.GetRows)
rs.Close
Set cn = Nothing
[a1].Resize(UBound(rsARR), UBound(Application.Transpose(rsARR))) = rsARR
End Sub
I dont even know if the bottom part of the code works, because an error message pops up that the file is not found. The interesting thing is, if I debug and copy the value of strcon into windows "run", it opens the correct file. So I guess the path is correct? Can I even open a .txt file through an ADODB connection? Right now I am a bit confused if this is possible and if it is the best solution.
Some more background regarding the text files I am trying to save into the array:
-They are output from another program, so it is always the same structure and very oreganized
it comes in this format:
Column a Column b ....
data 1 data 1
data 2 Data 2
...
and so on.
If possible, I would like to retain this structure, and even safe it as a table with the first row as column headers.
The Data Source is the folder path containing the file and the file is the table (SELECT * FROM ..). Replace "\\filename.txt" in strcon with the folder path.
http://www.connectionstrings.com/textfile/

Generate graph automatically based on a set of data table in excel using VBA

I'm very new in VBA.. Currently I'm on my project which required me to creating a automation tool by plotting 2 bar chart automatically based on 2 table data as shown below
However as the table data was generated out from another automation tool thus the number of rows can be increase or decrease. And the number of rows could be more/less than 5, I couldn't select the cells by specifying the address of the cell such as "A7" or "B6".
And these are the expected output of the chart:
Hope some kind soul could help me on this..
I don't think you need a macro.
All you need is some dynamic named ranges:
Microsoft Support
And set your data range to those named ranges.
If the different blocks of data in a given worksheet are separated by blank rows and columns, and the bloc you want is the only one containing the word "Date", you could use a simple VBA routine to find the word "Date", determine the block of data is sits within, and insert a chart using that data. Like the following:
Sub PlotRangeUsingFind()
Const SFind As String = "Date"
Dim rng As Range
On Error Resume Next
Set rng = ActiveSheet.Cells.Find(SFind).CurrentRegion
If Not rng Is Nothing Then
With ActiveSheet.Shapes.AddChart.Chart
.ChartType = xlColumnClustered
.SetSourceData rng
End With
End If
End Sub
You can modify this to look for any unique word in the block of data. It need not be the entire cell's contents; for example, you could use "Accepted" based on your screenshot.

VBA Excel vlookup in loop problem

I have a problem with my VBA code in an excel spreadsheet containing orders. Each row contains a customer number, which I use to look up the customer email address, contained in a different sheet in the workbook.
The vlookup code works fine for a single cell, but the problem is when I try to loop through all of the rows of the spreadsheet. The Excel formula for a single cell is, e.g.,
=VLOOKUP(B2,Customers!A2:D1000,4,FALSE)
The VBA code generated for this is:
Range("M2").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-11],Customers!RC[-12]:R[999]C[-9],4,FALSE)"
Incorporating this into a loop, after selecting the starting cell, I have the following:
Cells(2, 13).Select
Do
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-11],Customers!RC[-12]:R[999]C[-9],4,FALSE)"
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell.Offset(0, -10))
The problem is that I want the "table array" to be fixed, not relative to the cell whose value is being looked up. But I absolutely can't figure out how to do it. If I change the code as follows, I get a run-time error:
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[-11],Customers!A2:D1000,4,FALSE)"
I have tried quoting, unquoting, setting a range variable, using the range variable with .address... can someone please help?
Thank you so much.
I'm pretty sure the brackets in your R1C1 formula indicate that you are specifying a relative range (especially with the negatives in them). If you want to specify an absolute range, you need to specify the R1C1 cells without brackets; e.g. R2C2:R4C4.
As a simple example:
Sub test()
Sheet1.Range("C5").FormulaR1C1 = "=VLOOKUP(1,R1C1:R3C3,2,FALSE)"
End Sub
Running this gives you an absolute "A1"-style formula in cell C5.
I think your problem might be:
Customers!RC[-12]:R[999]C[-9]
Because it is a relative range. You have to explicitly specify where your data table is; e.g. Customers!RC12:R999C9 (you need to figure out where it is on your sheet).
An easy way of figuring this out is highlighting your data table on your worksheet, then switch to the Visual Basic Editor and manually run this (put your cursor inside of the Sub, and press the 'Play' button or go to Run->Run).
Sub test2()
Dim r As Range
Set r = Application.Selection
InputBox "your r1c1 range:", , r.Address(True, True, xlR1C1)
End Sub

Resources