I have got a table in access that I loop through using a DAO recordset. For every recordset I take a bunch of data to an excel spreadsheet and run it through a model in excel. This produces a bunch of results in excel which are calculated in named cells.
I want to be able to update the current recordset in access with these results but am having a tough time doing it.
I have the following code
code to create a DAO recordset
code to move to first record
code to parse data to excel
code to run a bunch of stuff in excel including a goal seek to calculate results
next I use the follwoing code without success
With MyXL
strSQL = "UPDATE ProductPricing SET Profit = " & .Names("Profit") & ";"
End With
Code to move to next record and loop until EOF
Could you not try to keep everything in access and replicate the goal seeking using a user defined function? Failing that I would keep the code in excel and get the code to “pull” the values into excel and then “push” them to access as opposed to pushing the data to excel and pulling it back
Related
I want to automatically download financial data by using Excel and save that data. The download of the data is done by an Excel add-in. ISINs are used as the data identifier. The process looks as follows:
Open Workbook
Replace the existing ISIN with a new one
Download data
Export data
Close file
The data download is done by a custom function which is defined inside the Excel Add-in (and which I cannot access as it is password protected): INFGETHIST(), one function parameter is an ISIN. Unfortunately, the function does not load the data until the VBA macro I am using to update the ISIN and close the workbook afterwards is fully executed - which means, the workbook gets closed before the data is updated.
I've tried the following
Application.CalculateFullRebuild
Calculate and
Sub WaitUntilFinished()
Application.Calculate
If Not Application.CalculationState = xlDone Then
DoEvents
End If
End Sub
but to no avail.
I'm searching for a way to trigger the download of the data before my code executes completely. Any ideas much appreciated.
I have been battling with this issue for a couple of days and read a lot of posts about renaming connections and still cannot achieve what I need to.
Essentially I have a workbook that has multiple sheets each with a different pivot table using a different connection.
I need to use VBA to insert date range criteria from a "Control" tab into the sql statement of each connection because as we all know pivots can't use the ? parameter.
However, as we also know, Excel renames the connection when you modify it, so changing the command text with VBA ends up creating new connections and leaving redundant ones.
Using some other very useful posts in this forum I have successfully managed to
- change the command text
- delete the old connection and rename the new one assuming its name to be "Connection"
thus:
text = "... new SQL query here..."
ActiveWorkbook.Connections("GLCosts").ODBCConnection.CommandText = text
' assume excel has renamed the "GLCosts" connection to "Connection"
ActiveWorkbook.Connections("Connection").Refresh
' delete the original and rename the new one to the old name
ActiveWorkbook.Connections("GLCosts").Delete
ActiveWorkbook.Connections("Connection").name = "GLCosts"
As long as each Sub() does this in turn then it should be fine as the "new" connection name will always be "Connection" (i.e. not "Connection1" etc)
HOWEVER
What I have found is that Excel only renames the connection IF THERE IS A CHANGE TO THE COMMAND.TEXT
Therefore, if the user doesn't actually change the date criteria values (held in Sheets("Control").Range("D4")) but DOES run the macro to refresh the pivots then the macro fails because the command text hasn't been modified, and there's no new connection string to rename as the old name.
So....
I tried to be clever. In each Sub() I first set text = "... a valid sql query but not the one i want...", then replace the command.text of the connection with this dummy query thus forcing excel to create a new connection which I can rename. Then when i set text = "...the correct sql query" excel will again create a new connection called "Connection" and I can repeat the renaming and deleting steps.
This should have been fine but for some reason it just crashed excel and I haven't tried it again
Does anyone have an actual solution to this? Should I try the clever stuff bit again?
Any ideas gratefully received
I have also encountered this bug when updating the CommandText property of an ODBC connection. I found that if you temporarily switch to an OLEDB connection, update your CommandText property and then switch back to ODBC it does not create the new connection. Don't ask me why... this just works for me.
Create a new module and insert the following code:
Option Explicit
Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")
With WorkbookConnectionObject
If .Type = xlConnectionTypeODBC Then
If CommandText = "" Then CommandText = .ODBCConnection.CommandText
If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
.ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
ElseIf .Type = xlConnectionTypeOLEDB Then
If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
Else
MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
Exit Sub
End If
If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
.OLEDBConnection.CommandText = CommandText
End If
If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
.OLEDBConnection.Connection = ConnectionString
End If
.Refresh
End With
End Sub
This UpdateWorkbookConnection subroutine only works on updating OLEDB or ODBC connections. The connection does not necessarily have to be linked to a pivot table. It also fixes another problem and allows you to update the connection even if there are multiple pivot tables based on the same connection.
To initiate the update just call the function with the connection object and command text parameters like this:
UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"
You can optionally update the connection string as well.
Here's what I do, which doesn't rely on hard-coded references, to manage the annoying process of programmatically updating the pivotCache in Excel.
First, before you have VBA alter your existing Pivot Cache/Connections, declare a string variable (currentPvtConn) in your code and set value to the current Pivot Cache name for the Pivot you intend to refresh. Also, delcare a second string variable (newPvtConn) to hold the name of the new connection Excel will undoubtedly generate...
Dim currentPvtConn As String
Dim newPvtConn As String
currentPvtConn = ActiveSheet.PivotTables("pvtUser").PivotCache.WorkbookConnection
...Now place your code to modify the CommandText...
After the refresh commands execute, Excel will create that dastardly new connection named "Connection#" and you'll be left with the old, untouched one as well. To clean up this mess, we'll need to capture the newly created connection name and store in the newPvtConnection variable we created earlier...
newPvtConn = ActiveSheet.PivotTables("pvtUser").PivotCache.WorkbookConnection
Since you now have both names stored as local variables, you can actually comare the two strings and
Finally, delete the orignal connection and rename the newly-created one. IF statement ensures a new connection was acually created before deleting/renaming anything.
If (StrComp(currentPvtConn, newPvtConn) <> 0) Then
ActiveWorkbook.Connections(currentPvtConn).Delete
ActiveWorkbook.Connections(newPvtConn).Name = "[My Original Connection Name]"
End If
... put rest of code
I'm exactly not sure why yours is crashing. I did find an obscure reference/solution to a problem where the following occurs:
Create Excel file with parameterized queries that load directly to Pivot Cache (i.e. using parameters in the command text "?")
Save beatufully-crafted file and close
Re-open and try to refresh
Excel crashes hard and closes; no chance of "repairing"
/***
Apparently, parameters aren't supported in Pivots. The problem lies in the parameter cells in a spreadsheet. Actually, when you close the file, query "forgets" what the parameter cells are, and uses blanks instead. That is why Excel crashes. I guess this is caused by the fact that pivot tables "can not be used" against parameter queries. However... Here is my workaround: no additional table necessary - only pivot table.
Create common query first (no parameters.)
Create pivot table based on query results.
Change query to parameter query.
Before refreshing data in Excel do not select cell values as parameters.
Instead, use prompt: Connection Properties=> Parameters=> "Prompt for value using following string:".
So, when you click "Refresh" on your pivot table, you will be prompted to enter parameters.
I know it is not as elegant as referring to a cell, but in this way Excel will not crash. Besides, you will not have to refresh both result and pivot table, but only pivot table.
Source MSDN: (bottom-of-page comment)
***/
I have also encountered this problem. I know the thread is old but I thought I'd share a workaround anyway.
I am using Excel 2013 (although it may also work in earlier versions), and discovered that when changing the ODBCconnection.commandtext in VBA I get the same effect, where a new connection called 'Connection' is created with the old command text and is linked to the pivot table. But the original connection has the new command text however it's not connected to the pivot any more.
If the connection you want to change in VBA is linked to an excel table rather than a pivot table, I found that the new 'connection' is not created, and instead the original connection is changed by the code yet remains linked to the table.
So I created a connection linked to an excel table on a hidden worksheet, then used this table as the source of the pivot table.
I hope this helps someone, as I was scratching my head over this for days.
I have the following code in excel VBA
'Create query table to hold the rates.
With objBK.Worksheets(1)
Set objQT = .QueryTables.Add( _
Connection:="URL;https://xxx.output=XLS", _
Destination:=.Range("A1"))
End With
https://xxx.output=XLS return an XLS table that is written in A1 cell of my worksheet.
The problem is that every time I run this query it keeps adding the table in A1 shifting the previous table and NOT overriding it.
How can I override old table?
You keep adding new ones when you actually want to adjust the existing one. Give your QueryTable a name (objQT.Name = "blah"). Then when you need to adjust it, get hold of that QueryTable and make your adjustments to it.
Alternatively, just delete the old one before creating a new one.
I have an automated process that is mostly run in Access. But, in the middle, it puts some data in Excel to scrub it into the correct form (it's much faster than doing it in Access), and at the end it opens another Excel file and puts data from some Access queries into the Excel file. For these connections from Excel to Access, I accomplished them all by going into Excel and doing Data --> Get External Data --> From Access, then selecting the Access file and the query I want to get the data from and tell Excel to make it into a Table.
So, I do that one time and then I want to be able to run this automated process that simply refreshes the data. To do this refreshing of the data, I do a line like:
Worksheets("Data").Range("A1").ListObject.QueryTable.Refresh _
BackgroundQuery:=False
The problem is, half the time (and I can't figure out why it does it one time and not another), it says "Do you want to connect to path\filename?" Of course I do, how else would the table refresh? So, this stops the automation. Even if I click Yes, I still can't get it to continue on. If I click Yes, it opens up the Data Link Properties. After I click OK for that, it opens a window titled "Please Enter Microsoft Office Access Database Engine OLE DB Initialization Information". It has info in it, including the path and name of the data source I want to access, but if I click OK, it says, sorry that didn't work, would you like instead to connect to (and then it lists the exact same path and file name it just said didn't work). It repeats the steps I just mentioned, and after that it errors out.
In case it matters, here is the (basic idea) code I use to connect to Excel from Access:
Public Sub ExportToExcel()
Dim ObjXLApp As Object
Dim ObjXLBook As Object
Dim ExcelFilePath As String
ExcelFilePath = CurrentProject.Path & "\"
Set ObjXLApp = CreateObject("Excel.Application")
Set ObjXLBook = ObjXLApp.Workbooks.Open(ExcelFilePath & "filename.xlsm")
ObjXLApp.Visible = True
' Runs the "DataSetUp" macro in the Excel file.
ObjXLApp.Run ("DataSetUp")
' The DataSetUp macro saves the Excel file
' Quit Excel
ObjXLApp.Quit
' Free the memory
Set ObjXLBook = Nothing
Set ObjXLApp = Nothing
End Sub
I have no idea how to fix this! Any help would be much appreciated.
This may be happening because your access database is still open from which the new excel file needs to input data back into. The database cannot be open when this takes place, hense the reason why excel errors and asks for another location to connect to.
So, I would work on generating the needed scrubbing via vba inside access probably.
I've got an Access 2007 database on which I have created around 15 SQL queries to process specific data, I have created a main frame navigation menu using menus in Access, I now need to extract all th queries to Excel using VBA code, I have managed to do this with the code below by creating a button and specifying this code to it.
Private Sub query1_Click()
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, "Total Users and Sessions", _
"C:\UsersandSessions.xls", , "Total Users & Sessions"
End Sub
Now my problem at the moment is that fine the query is exported to Excel, but it is done so without any formatting applied at all, I would like to add some formatting at least to the headers and maybe a title inside the spreadsheet, and one thing I dont really like is that all records are being started from the first cell. Also I would prefer that if I hit that button again in Access and the Excel spreadsheet has already exists with that query output then when clicked again it will write again to a the next available sheet.
Any suggestions or ideas a very welcome.
The short story, is you can't. You might be able to do some scripting on the Excel side to format the resulting file. If you want something pretty, you probably want to create a report.
You could, instead mount the excel sheet as a table, and then on a separated sheet in the excel file, reference the first sheet, and format the second sheet for viewing.
if you use DoCmd.TransferSpreadsheet and create an original and then edit it so that the formatting is correct, you can then run DoCmd.TransferSpreadsheet again and it will update the file with the values but keep the formatting.
However, if a human then changes the file by adding new tabs, or adding calculations, etc, then the DoCmd.TransferSpreadsheet will no longer work and will fail with an ugly error message. So what we do in our enviroment is DoCmd.TransferSpreadsheet to an original file with formatting, and follow that up in the VBA by copying the file to the users desktop, and then opening that copy so the user doesn't mess up the original source excel file.
This approach is a minimum code, clean, and easy to maintain solution. But it does require a extra "source" or original file to be hanging around. Works in Access 2007.
You also would like the results to end up on a new tab. Unfortunately, I think it will take some excel automation to do that. The VBA inside Acccess can call a function inside the VBA in Excel. That VBA could then copy the tabs as needed.
My idea would be a hybrid of Excel automation from Access and creating a template in Excel as well that would have a data table linked to your query.
To start create your data table in Excel. You can start three rows down and two columns to the right if you want or wherever. Go to your data tab and click access, find your db, choose your query you want to link to, choose table as the radio button but click properties next instead of ok, uncheck the enable background refresh, this part is critical ... under the definition tab in the connection string you will see a part that says Mode=Share Deny Write change that to Mode=Read, this will make sure that the query refreshes without errors from an MS Access VBA while the db is open and will keep your users from writing back to the db in case your query is a writeable query. Once you set that up you can adjust the table formatting however you choose from the table design tab and it will keep that formatting.
For the purposes of this we are going to assume you started the table in cell B4 ,and your named the worksheet CurrentDay, for purpose of the following VBA example be sure to replace that reference with your actual placement.
Next go back to Access and write your VBA first ensure that in your VBA window you have the reference to Microsoft Excel 12.0 Object Library is selected by going to Tools > References and selecting it from the alphabetical listing.
Create your sub as follows:
Sub query1_click()
Dim xl as Excel.Application
Dim wbk as Excel.Workbook
Dim wks as Excel.Worksheet
Dim RC as Integer
Dim CC as Integer
Set xl = New Excel.Application
Set wbk = xl.wbk.Open "X:\Filelocation\FileName.xlsx" 'name and path you saved the file you previously created
xl.Visible = True
'The above is not necessary but you may want to see your process work the first few times and it will be easier than going to task manager to end Excel if something fails.
RC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("B:B")) + 3 'This will count the rows of data in your table including your header so you can copy the data to another tab dynamically as the size of your table expands and shrinks we add 3 to it because we started at row 4 and we need the location of the last row of the record set.
CC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("4:4")) + 1 'This counts the header row and adds one space because we will use this as a location holder for our copy / paste function
Set wks = xl.wbk.Worksheets.Add
wks.Name = format(date(),"MM_dd_yy") 'this will name the tab with today's date... you can eliminate this step if you just want the sheets to be the generic Sheet1, Sheet2, etc.
With xl.wbk
.Worksheets("CurrentDay").Range(Cells(4,2),Cells(RC,CC)).Copy
.wks.PasteSpecial xlPasteValues 'This pastes the values so that the table links do not paste otherwise every tab would just refresh everyday.
.wks.PasteSpecial xlPasteFormats 'This gets your formatting.
.RefreshAll 'This will refresh your table
Wend
With xl
.Save
.Close False
.Quit
Wend
Set xl = Nothing
Set wbk = Nothing
Set wks = Nothing
End Sub
That should get you to have your data to not start on A1 of your sheets, save your old data each time, and automate the steps from access.