So I'm importing data every day into Access to use for reporting. The data comes from several spreadsheets created by different individuals. Because those individuals like to format things incorrectly I created a macro that reformats their document so that it can be imported cleanly into Access for me to use. Works great but it gets tedious having to open up each Excel sheet to run this Macro.
What I'm trying to do is place the Excel Macro in Access and then run the formatting code before importing it all at once. I am a bit lost in approaching this. I'm aware of ways to run Macros already placed in Excel sheets but is there a way to run a macro that is stored in Access that works in excel. I also thought to maybe inject the Macro into the excel document and then run it.
To sum things up, what I'm hoping to do is from Access, store a macro, that can be used to alter Excel Files.
Is this at all possible? If so How? Is there another approach?
What you are asking to do is automate Excel from Access. Yes, you can do this. In Access, add a module, add a reference to the Microsoft Excel object model (Tools: References), and use this framework code to get you started:
Sub PrepExcelFileForImport()
Dim xl As Excel.Application
Dim wbk As Excel.Workbook
Dim wst As Excel.Worksheet
Set xl = CreateObject("Excel.Application")
With xl
.Visible = True
Set wbk = .Workbooks.Open("c:\temp\temp.xlsx")
Set wst = wbk.Worksheets("data")
With wst
' add your formatting code here, be sure to use qualified references, e.g.
.Rows(1).Font.Bold = True
End With
End With
wbk.Close SaveChanges:=True
xl.Quit
End Sub
Related
I am looking at inserting/pasting a range of text data (40 columns) from Excel into bookmarks in Word. Most of the answers are done using Excel VBA, which is so not practical for my use case as I will have the Word document open, add a button that would run this 'import data' macro. I actually already have a button in the doc that inserts images into bookmarks, so that's one more reason I don't want to do it via Excel VBA.
I know this is not great code, but for the lack of definite leads, I'm throwing it here and hope that this gives you an idea of what I'm trying to achieve:
Sub ImportData()
Workbooks.Open ("\Book2.xlsm")
ActiveWindow.WindowState = xlMinimized
ThisWorkbook.Activate
Windows("Book2.xlsm").Activate
Range("A1:AF1").Select
Selection.Copy
Documents("test.docm").Activate
Selection.GoTo What:=wdGoToBookmark, Name:="Overlay_1"
Selection.Paste
End Sub
PS: It would be great if I could sort of 'transpose' the 40 columns into rows as it is pasted in Word.
Here's an update to my code based off #Variatus 's advice:
Sub ImportData()
Dim wb As Workbooks
Dim ws As Worksheets
Dim objSheet As Object
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
wb.Open ("C:\Users\pc\Documents\Book2.xlsm")
Set objSheet = CreateObject("Excel.Application")
ActiveWindow.WindowState = xlMinimized
Set ws = Workbooks("Book2.xlsm").Sheets("Sheet1")
ws.Range("A1").Value.Copy
With objWord.ActiveDocument
.Bookmarks("Bookmark_1").Range.Text = ws.Range("A1").Value
End With
End Sub
I'm getting this error:
Runtime Error '91':
Object variable or With block variable not set.
Notice how I stuck with a single cell reference for now (A1). I'll just update my code as I learn along the way :)
When you click the button in your Word document you want the following sequence to be initiated.
Create an Excel application object. Make sure that a reference to Excel has been set (VBE > Tools > References) so that Excel's VBA objects are available.
Using the Excel application object, open the workbook. Create an object. Place the object in an invisible window.
Definitely forget about activating or selecting anything in either the workbook or your Word document. The latter is active and remains active from beginning to end. The bookmarks are points in your document you can reference and manipulate by name without selecting them. The Excel workbook is invisible. You can access any part of it using the Range object.
The data you want from your workbook are contained in Worksheets. Be sure to create an object for the worksheet you are about to draw data from.
Excel tables don't translate very well into Word tables. If you do want to go that way I suggest that you use VBA to create the table you want in Excel (transpose the data before you import them into Word). However, you may find it easier to first create the tables you want in Word and then just copy values from your Excel source into the word tables. That would involve taking one cell value at a time and placing it into one Word table cell. Transposing would be done by the algorithm you employ.
Close the workbook. Quit the Excel application. Set the Excel application = Nothing. At the end of your macro everything is as it was before except that your document has data in it which it didn't have before.
Each of the above six points will lead you to at least one question which you can ask here after you have googled the subject and written some code. In fact, I strongly urge you to create one Main procedure (the one which responds to your button click) and let that procedure call various subs which carry out the individual tasks and functions to support the subs. The smaller the parts you create the easier it is to write the code, to find questions to ask and get answers to them. If you plan your project well expect to have about 12 procedures in it by the time you are done. Good luck!
I bought a software (with a large database), and its output is a simple Excel workbook, not saved anywhere (no path), named generically "Book1", that simply pops up on my screen.
Every time I ask the software for this output, I need to copy the content of this workbook and paste into another workbook, a mother-workbook, as I named it, to consolidate all the data.
I have to repeat this action dozens of times a day, so I thought it would be a great idea to create some VBA code to automate this task.
So... I made a very simple one:
ActiveWorkbook.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
The problem is... Each time the software outputs a new workbook, it seems that it is created in a new instance of Excel, which my macro can't reach. I mean, I run the code, but nothing happens, because my mother-workbook doesn't find the generic, unsaved and located in another excel instance "Book1".
If I open the mother-workbook after the output is opened, OK, the code works, because both are in the same instance. But as I need to keep the mother-workbook open all the time, I can't do this. I don't want to save each new output file either. It would take me a lot of time.
I'm using the 2016 version of Excel, but already tried the 2010 as well. My OS is Windows 10 Pro.
Any thoughts?
This code should do it.
Dim xlapp As Object
Set xlapp = GetObject("Book1").Application
xlapp.ActiveWorkbook.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
xlapp.DisplayAlerts = False
xlapp.Quit
Note that you need to close "Book1" at the end of your code to make sure that the next time an Excel file is created it will also be called "Book1" and not "Book2". And might as well close the Excel instance while we are at it!
For more information on the GetObject function, you can have a look at this page
Thanks a lot, DecimalTurn and Patrick Lepelletier!
The GetObject really helped me. The "closing" command worked better like this:
Sub CollectA()
Dim oApp As Application
Dim oWb As Workbook
Set oWb = GetObject("Book1")
Set oApp = oWb.Parent
oWb.ActiveSheet.Range("A1:C32").Copy
Workbooks("Mother-Workbook.xlsm").Worksheets("Sheet1").Range("B6:D37").PasteSpecial Paste:=xlPasteValues
oWb.Close False
oApp.Quit
End Sub
Cheers!
When you have more than one Excel file open, and your VBA/VSTO code calls the Calculate function, or turns on Automatic Calculation, Excel will painfully recalculate all open Workbooks, not just the active Workbook.
This is a well-known and well-reported problem, which has been around for years, but Microsoft doesn't seem interested in fixing it.
Calculate only the active workbook before saving
Microsoft Excel wishlist: Workbook level calculation
Ridiculously, in both VBA and VSTO, Microsoft gives us the ability to:
recalculate a particular Worksheeet
recalculate all open Workbooks
...but there's no option to just recalculate one particular Workbook.
In the financial company I work for, this is a huge issue. Our actuaries have big, bulky Excel files, full of formulae, and when they click on Calculate on one Workbook or we perform a calculate before saving a file, they then have to wait several minutes for all other open Excel files to also get calculated.
There are two ways around this.
You could run some VBA like this:
Application.Calculation = xlManual
For Each sh In ActiveWorkbook.Worksheets
sh.Calculate
Next sh
..but this isn't guaranteed to work. Your "Sheet1" might contain formulae pointing to cells in "Sheet2", but other cells in "Sheet2" might have dependencies back on "Sheet1". So, calculating each Worksheet once might not be enough to perform a full calculation on your Workbook.
Alternatively, you could open each Excel file in a separate instance (by holding down ALT as you open the Excel icon). But then, you lose the full Excel cut'n'pasting functionality, as described here:
Can't fully cut'n'paste between Excel instances
So, my question is... has anyone found a workaround for this issue ?
I just want to recalculate the cells in the Active Excel Workbook.
I wondered if I could add some VBA or VSTO which sets all non-Active Workbooks to "read-only" before I kick off a Calculation on the Active Workbook, thus preventing other Workbooks from being able to be recalculated. But this isn't possible. The "Workbook.ReadOnly" can only be read, not programmatically set.
Or perhaps adding a handler to the Worksheet_Calculate event, which checks if that VBA code which is being run belongs to the Active Workbook, and if not, it aborts attempting to calculate...? But this event actually gets kicked off after that Worksheet has been calculated, so it's too late.
Our company can't be the only one suffering from this issue...
Any advice (other than upgrading to Lotus 1-2-3) ?
This method uses another instance of Excel to avoid multiple workbook calculations. A few lines of the code for using a new instance were taken from this SO question, which deals with a similar topic and may be of interest to you.
You will have to test this for speed in your specific case, since the closing/opening time might not out-weigh the avoided calculations!
Macro steps
Set calculation to manual
Save and exit the desired workbook
Open it in a new instance of Excel
Recalculate
Save, close and re-open in original instance of Excel.
Key point for running this script:
The macro cannot live within the workbook to be recalculated, since it gets closed (twice) during the process. It should be placed in some other "utility" workbook.
Code - see comments for details
Sub CalculateWorkbook(WB As Workbook)
' Store path of given workbook for opening and closing
Dim filepath As String
filepath = WB.FullName
' Turn off calculation before saving
Dim currentCalcBeforeSave As Boolean
currentCalcBeforeSave = Application.CalculateBeforeSave
Application.CalculateBeforeSave = False
' Store current calculation mode / screen update and then set it to manual
Dim currentCalcMode As Integer, currentScreenUpdate As Integer
currentCalcMode = Application.Calculation
currentScreenUpdate = Application.ScreenUpdating
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
' Close and save the given workbook
WB.Close savechanges:=True
' Open a new INSTANCE of Excel - meaning seperate calculation calls
Dim newExcel As Excel.Application
Set newExcel = CreateObject("Excel.Application")
' Could make it visible so that any problems don't leave it hidden in the background
' newExcel.Visible = False
' Set the calculation mode to manual in the new instance sothat the workbook isn't calculated on opening.
' This can't be done without an existing workbook object.
Dim tempWB As Workbook
Set tempWB = newExcel.Workbooks.Add
newExcel.Calculation = xlCalculationManual
newExcel.CalculateBeforeSave = False
' Open the workbook in the new instance of Excel
Dim newWB As Workbook
Set newWB = newExcel.Workbooks.Open(filepath)
' Calculate workbook once
newExcel.Calculate
' Close and save the workbook, tempworkbook and quit new instance
newWB.Close savechanges:=True
tempWB.Close savechanges:=False
newExcel.Quit
' Re-open in the active instance of Excel
Application.Workbooks.Open filepath
' Reset the application parameters
Application.CalculateBeforeSave = currentCalcBeforeSave
Application.ScreenUpdating = currentScreenUpdate
Application.Calculation = currentCalcMode
End Sub
Call the above sub by passing it the workbook object you wish to recalculate (this could be done from a button etc).
This has been tested on a very simple example workbook, and the concept works. However, please test on a copy of your workbook first, since it has not been fully robustness tested, and has no error handling.
The method I use for this in my FastExcel product involves setting WorkSheet.EnableCalculation to false for all the worksheets in all non-activeworkbooks and to True for all the worksheets in the active workbook.
This works but has the disadvantage of making the next calculation a Full calculation of the new active workbook when you change the active workbook: so its a tradeoff.
You can try this out in your situation by downloading the trial version of FastExcel from Download the 15-day full-featured trial of FastExcel V3 build 231.655.789.380
Then use FastExcel Calculation Options and check the Active Workbook checkbox in the Current Calculation Mode settings;
Disclaimer: I own, develop and market the FastExcel product. The FastExcel component that contains the Active Workbook Calculation code is FastExcel V3 Calc
While generating hundreds of Office Excel spreadsheets with Office Access is certainly possible, it would be great to add macros to the generated workbooks.
I would like to add the functions to the object "ThisWorkbook" in the VBA project for each spreadsheet on generation. How would one go about doing this?
Thank you in advance!
Under the assumption that the macro's in all generated workbooks are the same,
create a template containing all VBA code (and optionally constant text like headers, footers, print range definitions, etc. - i.e. "everything except data")
create any new workbook from the template
insert your data into the WB object
save as macro enabled worksheet (Excel 2007/2010)
close it
example
Sub CreateWB()
Dim WB As Workbook
Set WB = Workbooks.Add("MacroTemp.xltm") ' contains VBA, ActiveX, etc.
WB.Worksheets("Sheet1").[A1] = "co-cooo!" ' adding data
WB.SaveAs "MyGenWB", xlOpenXMLWorkbookMacroEnabled
WB.Close
End Sub
In Excel 2007/2010 do not forget to save the template as macro enabled template (*.xltm").
I am relatively new to the true power in Excel - Macros/VBA and have been tasked to set up the financial model for a million dollar project. I am able to set everything up and have it run smoothly, but there's too much manual input involved. I would like to seek simplification through the power of VBA.
This is my dilemma:
I need to be able to individually double-click on a specific set of cells (in a Row), which will open up a file window that allows me to select a EXL file.
Once I select the file, that file should be preferably opened in a temp status (not visible, but I can run functions and pull info from it).
I will then need the macro to go into that opened sheet, conduct a simple SUMIFS function, and record the outcome in a column of the current sheet I'm working from.
I've been doing some Excel tutorial on Lynda in hope to seek the answers there, but I think the complexity of this request demands the knowledge of a true master.
Any help will be greatly appreciated! I would imagine this could be a nice little challenge for those who seek it :)
Sincere thanks,
Try this:
Dim appExcel As Excel.Application
Set appExcel = CreateObject("EXCEL.Application")
Dim wkbk As Excel.Workbook
Set wkbk = appExcel.Workbooks.Open(sPathSrc, , False, , , sPassword)
' do EXCEL work here
If Not wkbk Is Nothing Then wkbk.Close True
Set wkbk = Nothing
If Not appExcel Is Nothing Then
appExcel.DisplayAlerts = False
appExcel.Quit
End If
Set appExcel = Nothing
This code is from an ACCESS application that invoked EXCEL to print some reports. I found it necessary to sprinkle some DOEVENTS calls around, but it was all a while ago; some details escape me at this moment.