I'm subscribed to a RTD financial application with the option to export real time data to Excel via DDE. So, using the DDE copy/paste app option, I've created a Excel table with real time DDE financial data. Cells actually contains DDE formulas. Now I open, refresh and save table manually, but what I need is a solution that will open, refresh the data, save and close this excel table automatically.
I didn't now how to attach the file, so here is a screenshot of it.
My Excel DDE file
Since I'm new to vba and vbscript, I was searching internet for a solution but without any success, especially not for automatic update (refreshment) of the DDE data.
What I've been doing for the past few days, was searching, trying and customising different kind of vba macros and vbscripts, and today I'm completely lost and confused.
I have tried bunch of suggested solution, even yours
Refresh data and exit with saving Macro Excel
and On workbook open, Excel Macro to refresh all data connections sheets and pivot tables and then export the pivot to csv but in my case they don't work.
Any solution, reference, code example will be greatly appreciated.
Kindly try the below one and
be careful when using
Application.Calculation = xlCalculationManual
Application.Calculation = xlCalculationAutomatic
this sets the entire excel application to calculate formula's either automatically or manually. If you use
Application.Calculation = xlCalculationManual
you'll notice your automatic formulas no longer work.
Thanks for the reply #mulla, but this doesn't work. In vbscript I get runtime error and in vba nothing happens (does not affect refreshment). The same thing is for the Worksheet.Calculate.
Than I recorded a macro upon manual update of the links (data) in order to inspect how Excel proceed update and this actually works, but not all the time. If I open Workbook manually and I keep it opened than whole export works perfectly since the data is constantly refreshed (not what I need). In case when the Workbook is opened via vbscript only (what I need), as you can see in the output below some of the values are exported successfully (for the faster refreshment I believe) and some are #N/A (for the slower refreshment). All the data is refreshed every second, except upon opening the file where successfully exported values are refreshed instantly and #N/A values need few seconds (2-3s) to be refreshed.
Recorder macro uses ActiveWorkbook.UpdateLink as follows (the code below is for the first row, but the same logic is used and for the rest of the rows):
Sub PriceUpdate()
ActiveWorkbook.UpdateLinks = xlUpdateLinksAlways
ActiveWorkbook.UpdateLink Name:= _
"vegadde|VEGA!897789,148,1#""1,\""12,0,0\"""",1", Type:=xlOLELinks
ActiveWorkbook.UpdateLink Name:= _
"vegadde|VEGA!897789,148,1#""1,\""12,0,0\"""",3", Type:=xlOLELinks
ActiveWorkbook.UpdateLink Name:= _
"vegadde|VEGA!897789,148,1#""1,\""12,0,0\"""",4", Type:=xlOLELinks
...
End Sub
Then I use vbscript to call the macro and export data in CSV comma delimited file with timestamp name:
Option Explicit
Dim objExcel, objBook, objSheet
Set objExcel = CreateObject("Excel.Application")
Set objBook = objExcel.Workbooks.Open ("d:\exptest\exptest.xlsm", 0, False)
'Set objSheet = objBook.Worksheets.Item(1)
objExcel.DisplayAlerts = False
objExcel.Run "PriceUpdate"
WScript.Sleep 5000 ' Delay in order to update links
objBook.SaveAs "d:\exptest\" & Year(Now) & "." & Month(Now) & "." & Day(Now) & "_" & Hour(Now) & "-" & Minute(Now) & ".txt",6
objBook.Close False
objExcel.DisplayAlerts = True
objExcel.Quit
'Set objSheet = Nothing
Set objBook = Nothing
Set objExcel = Nothing
And what I get is the following uotput:
Inst,Price,Datetime
USD,1.1015,7/22/2016 12:48
GBP,#N/A,#N/A
CHF,#N/A,#N/A
SEK,9.4962,7/22/2016 12:48
NOK,#N/A,#N/A
JPY,#N/A,#N/A
DKK,#N/A,#N/A
CAD,#N/A,#N/A
AUD,1.47395,7/22/2016 12:48
RUB,71.0082,7/22/2016 12:48
I'm struggling to learn Excel logic behind different updates in order to solve my problem and to get desired solution, but with no success.
And this is only a test file with 22 links. The real one has 482 links that need to be updated.
Marjan. Not sure if this is still a problem for you, but I ran into a similar problem with refreshing RTD data in a closed Excel workbook and seem to have found a solution. As you mentioned, when you open the workbook, the data refreshes automatically (with some of the more complex data points taking 2-3 sec). The problem is, you don't want to have to constantly manually open a workbook to refresh data. And I've found that the data fails to refresh with methods like RTD.RefreshData called to a closed workbook.
So to fix this, I created a vba module that simply opens the workbook, refreshes it, pauses for a second (you may need 2-3 more seconds for all data to update) and then saves and closes the workbook. This method is called recursively. Essentially this does the work of constantly opening and closing the workbook, while delaying briefly so that the RTD data can refresh. So far, this is able to provide refreshed RTD data successfully (although there is an inherent slight delay of a few seconds). Here's the basis of my code:
Sub refreshXLS()
Path = "workbook.xlsm" 'the workbook path you want to refresh
Workbooks.Open Path
ActiveWorkbook.RefreshAll
Application.OnTime Now() + TimeValue("00:00:01"), "closeActive"
End Sub
Sub closeActive()
ActiveWorkbook.Save
ActiveWorkbook.Close
refreshXLS
End Sub
Hope this helps if you still wish to solve this problem!
Related
I am having an vba problem with Excel. So I have this workbook, "Book Tool - Updated Feb. 2017.xlsb", that I am currently updating and will distribute to about 10 team members to use to keep track of their work. What I am trying to do is lookup data from an outside document, "Team Data", put that in Column DE of the "Book Tool - Updated Feb. 2017.xlsb" file. So I wrote the below code, where when the team member pushes a button, it opens up the lookup file, looks for the data in Column A of the "SICcode" sheet of that external file, matches it with Column B of the "Book Sheet" of the "Book Tool" file, and returns the value in Column D of the lookup file. It runs for the length of the "Book Sheet", closes the external file, and you get a popup that the data add is done.
Now when I did this code myself, it works great. Automatically opened the external document, did the lookups, returned the correct value, closes the external document, the pop up. So I sent the file with the macro to my manager to play around with before giving it to the rest of my team, but the macro does not work. When the macro runs, the external document opens, it seems like it is running through the lookups, closes the external file, and the pop up appears, but there is no value in the DE column, nor is there the lookup formula there. My manager didn't change the name of the Tool document, he didn't mess with any code. He emailed it back to me and with that copy the formula isn't working, but I checked it with my master copy formula and even though it's the same, the macro will not populate the data.
We have to keep the external data in a separate file, because otherwise the tool with the lookup data is over 2MB and takes forever to run or crashes.
Is there something about emailing the tool back and forth that messes with the file, or is there some formatting issue I need to look into that causes it not to work? With my master copy on my computer, the code always works regardless if I work in a virtual desktop, have it in a different folder, whatever.
I am just okay with vba, I don't know all of the technicalities of this process, so maybe I am overlooking some flaw with how I've set it up or limitations Excel has. Any guidance or help would be appreciated.
Sub AddData()
On Error Resume Next
'Open External Data Source
Workbooks.Open Filename:= _
"W:\USB\Reporting\Book Tool\Attachments\Team Data.xls"
'View sheet where data will go into
Windows("Book Tool - Updated Feb. 2017.xlsb").Activate
'Gets last row of Tool sheet
Sheets("Book").Select
lastrow = Cells(Rows.Count, "B").End(xlUp).Row
'Lookup in External File
Sheets("Book").Select
Range("DE2:DE" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-108],'[Team Data.xls]SICcode'!C[-109]:C[-104],5,FALSE)"
'Close External Data File
Windows("Team Data.xls").Activate
ThisWorkbook.Saved = True
Application.DisplayAlerts = False
ActiveWindow.Close
MsgBox "Data Add Done"
End Sub
Be sure to properly qualify your statements, and also it would be wise to assign the appropriate workbook to a variable. See the modified code below:
Sub AddData()
On Error Resume Next ' I also suggest removing this since it wont warn you on an error.
Dim wb as Workbook
Dim wbExternal as Workbook
Dim ws as Worksheet
Dim wsExternal as Worksheet
'Open External Data Source
Set wbExternal = Workbooks.Open Filename:= _
"W:\USB\Reporting\Book Tool\Attachments\Team Data.xls"
' Depending on the location of your file, you may run into issues with workbook.Open
' If this does become an issue, I tend to use Workbook.FollowHyperlink()
'View sheet where data will go into
' Windows("Book Tool - Updated Feb. 2017.xlsb").Activate
' Set wb = ActiveWorkbook
' As noted by Shai Rado, do this instead:
Se wb = Workbooks("Book Tool - Updated Feb. 2017.xlsb")
' Or if the workbook running the code is book tool
' Set wb = ThisWorkbook
'Gets last row of Tool sheet
Set ws = wb.Sheets("Book")
lastrow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
'Lookup in External File
Set wsExternal = wbExternal.Sheets("Book")
wsExternal.Range("DE2:DE" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-108],'[Team Data.xls]SICcode'!C[-109]:C[-104],5,FALSE)"
'Close External Data File
ThisWorkbook.Saved = True
Application.DisplayAlerts = False
Windows("Team Data.xls").Close
MsgBox "Data Add Done"
End Sub
I would also recommend browsing through SO for tips on avoiding .Select and .Activate as this can make your code unreliable and in some cases can slow down your code significantly.
Lastly, if performance is a concern you may want to look into loading your lookup values into arrays and finding the corresponding values this way. It will completely depend on what kind of data you are working with. I had a workbook using filldown vlookups that went from running in a matter of 5-10 minutes or more to consistently running in less than 20 seconds by replacing VLOOKUPS with for looping arrays.
I want to delete all hyperlinks on currently active sheet via VBA.
For that I am using ActiveSheet.Hyperlinks.Delete command, which works fine and does not take virtually any time...
All that until I have opened two workbooks containing hyperlinks at the same time. In that case, the very same command takes much more time (minutes) to finish. It does its job, removing hyperlinks from the activesheet only, but in longer time. It seems somehow the other worksheets with hyperlinks is slowing it down.
I can have multiple workbooks opened at the same time, but they must not have any hyperlinks for the macro to work fast.
Can someone help me to overcome this?
I actually am in a situation where I frequently need to have both hyperlinks workbooks opened at the same time and running the macro which deletes hyperlinks.
This may not be ideal, but I'd consider starting your code with a check to see if other workbooks are open in the instance and if they are save the activeworkbook, open an new instance of excel and reopen the workbook in the new instance. Then run your code again.
Something like this to open the new instance:
Sub BlahBlah
if morethan1 then
CWb = ActiveWorkbook.name
ActiveWorkbook.save
Dim objXL
Set objXL = CreateObject("Excel.Application")
objXL.Visible = True
application.displayalerts = false
objXL.Workbooks.Open = CWb
application.displayalerts = True
end if
End Sub
If you isolate the workbook you should return to your normal runtime
I am trying to create a macro that would act the same as right clicking a workbook tab, selecting move or copy, checking the copy option, selecting another open workbook and clicking ok but without the warnings. I found the code to disable warning and I was able to record a macro that does what I want but I don't know how to make it request which open workbook to copy to.
In short how do I make the following code work where WorksheetIWantToCopy is the one the user currently has selected and OpenWorkbookIWantToCopyToo.xlsx is a workbook to be selected by the user out of a list of open workbooks.
Application.DisplayAlerts = False
Sheets("**WorksheetIWantToCopy**").Select
Sheets("**WorksheetIWantToCopy**").Copy Before:=Workbooks( _
"**OpenWorkbookIWantToCopyToo.xlsx**").Sheets(1)
I appreciate any information anyone can provide. My team greatly appreciates your support (we currently have to hit ok on 25 warnings due to conflicts we don't really care about). Thx!
If the worksheet you want to copy will always be the active sheet then you can use ActiveSheet.
As for letting the user select a workbook, it can be as simple as using the InputBox.
Public Function getWorkbookName() As String
Dim i As Integer, sListOfWbks As String, sRsp As String
' build list of workbooks
For i = 1 To Workbooks.Count
sListOfWbks = sWbkList & vbCrLf & i & " - " & Workbooks(i).Name
Next i
sRsp = InputBox("Select workbook." & vbCrLf & sListOfWbks)
If IsNumeric(sRsp) Then
getWorkbookName = Workbooks(CInt(sRsp)).Name
Else
' user pressed cancel or entered invalid text
getWorkbookName = ""
End If
End Function
This basic example will of course list all workbooks, including hidden add-ins and the workbook you are moving away from.
This needs to be said before anything else: always, always, ALWAYS make use of .Copy instead of .Move when automatically shuffling excel workbooks with VBA. Move has inherent risks because it is a modification of the other file, and if your code misbehaves then you could lose all of the data you're working with.
First of all, know which workbook is which, with no ambiguity:
Dim wkbkDestination, wkbkTemporary As Workbook
Set wkbkDestination = Workbooks("OpenWorkbookIWantToCopyTo.xlsx")
Set wkbkTemporary = Workbooks.Open("WorkbookIWantToCopy.xlsx")
Next, Copy your desired tab to your destination workbook, rename the new tab to prevent errors, and close the second workbook, without saving.
wkbkTemporary.Worksheets("WorksheetIWantToCopy").Copy Before:=wkbkDestination.Worksheets(1)
wkbkDestination.Worksheets(1).Name = "WorkbookIWantToCopy"
wkbkTemporary.Close SaveChanges = False
Naturally, depending on the exact controls you intend to use, there are lots of ways this code could be implemented. From your description it is somewhat unclear what exact problem you're trying to solve and whether this is a one-off event you're trying to accomplish for a given list of files, or whether this function is to be used on an ongoing basis.
Can Anyone tell me how do I undo all my changes to my workbook?
I have file excel1.xlsx and I have did sorting and many operations on the excel.xlsx using vba. But at the end I want the excel1.xlsx to be the same which was at the start. How do i Undo all my changes using vba?
activeworkbook.saved = True
I have found that it retains back all the contents as at the begginning but its not working.So is there any command where i can get back my original file after performing operations over it. Well yes
wb1.Sheets(1).Activate
ActiveWorkbook.Close savechanges:=False
It works but I dont want my workbooks to be closed it should be still opened. How do I make it? Thanks in advance.
In order to undo a sub routine, you can either choose not to save the file and just close it, or you have to write a special sub routine to save the state of the file, then restore the state (custom undo). This is one of the pains with sub routines is that they cannot be undone through normal undo. Most people, me including, will reccomend you work off a backup.
When making your custome undo routine, the big question is what do you need to save the state for? Saving all information about the file would be unnessesarily heavy, so it's good to know what you want to save.
Update:
This is a dirty way to backup the sheet if you only have 1 sheet of data. This is more of a proof of concept of one way to create a backup and not finalized perfect code. It just creates a backup copy of the currentsheet and when you'restore' you are simply deleting the original sheet and renaming the backup to what it used to be called. :p
How to test:
Put some data and value in your original sheet then run the Test() sub-routine!
Public backupSheet As Worksheet
Public originalSheet As Worksheet
Public originalSheetName As String
Sub CreateBackup()
Set originalSheet = Application.ActiveSheet
originalSheetName = originalSheet.Name
originalSheet.Copy After:=Sheets(Application.Worksheets.Count)
Set backupSheet = Application.ActiveSheet
backupSheet.Name = "backup"
originalSheet.Activate
End Sub
Sub RestoreBackup()
Application.DisplayAlerts = False
originalSheet.Delete
backupSheet.Name = originalSheetName
Application.DisplayAlerts = True
End Sub
Sub ZerosFromHell()
Range("A1:Z100").Select
Cells.Value = 0
End Sub
Sub Test()
Call CreateBackup
Call ZerosFromHell
MsgBox "look at all those darn 0s!"
Call RestoreBackup
End Sub
Short answer: you can't. Sorry.
Changes you make to your sheet using VBA cannot be undone at the click of a button or with a single, standard VBA statement.
The right thing to do would seem to be: do your VBA-driven work on a copy of the sheet, and delete/don't save this copy if you don't want to keep the changes (and reopen the original if you need to do so). But from your question, it sounds like you don't want to do that.
Your only alternative is then to write your own VBA procedure that backtracks all the changes you've done. Depending on what operations you performed, reversing them could be a ridiculously complicated thing to do, compared to just closing without saving and re-opening. But if you insist, by all means, knock yourself out!
Save a copy of the original workbook prior to running your macro. using the .SaveAs method at the beggining of the sub routine.
Run the VBA macro routine in the original workbook.
Now have a second macro "Undo VBA changes" that opens the workbook copy from step (1) , closes the workbook that ran the macro in Step (2) and calls the .SaveAs method again overwriting the existing workbook from step (2).
Note:
In order to get this UndoMacro to work you will need to put it in an Addin or a seperate workbook (an addin is cleaner). This will allow you to run the .SaveAs method and overwrite teh original workbook from Step (2) which will at this point have been closed to prevent an VBA runtime error message occuring.
If all of your data is cleanly organized, this works pretty well. Much like the OP, I needed to go back to the original state of an Excel file, and didn't want to have to re-load the original (it takes about 25 seconds to load, due to aged infrastructure, and slow PCs).
What I did was to copy all of the data into a variant array, do all of my processing to the workbook, then write back the variant array to the Excel file (data is on a worksheet called "Data", and starts at Row 2, and uses columns A through Z). While this uses a bit of RAM, the reading/writing is nearly instantaneous. Relevant code:
Dim varDataArray As Variant, wb As Workbook, ws As Worksheet, lngEndRow as Long
Set wb = ThisWorkbook
Set ws = ThisWorkbook.Worksheets("Data")
With ws
' This simply finds the last row with data
lngEndRow = .Cells.Find("*", [A1], , , xlByRows, xlPrevious).Row
' This reads all cell data from A2 to Z###, where ### is the last row
varDataArray = .Range("A2:Z" & lngNumberOfRows).Value
... do things ...
' This writes all the data back to Excel
' 26 is the numeric column equivalent to "Z"
.Range("A2").Resize(lngEndRow, 26) = varDataArray
End With
I have created an Excel Spreadsheet which helps with data analysis from an Oracle database.
The user enters then clicks the "Refresh Query" button which generates a query for Oracle to execute. The query takes a minute or so to complete. Although the VBA code does not hang on ".Refresh", all Excel windows remain frozen until the query completes.
Sub refreshQuery_click()
Dim queryStr as String
' Validate parameters and generate query
' ** Code not included **
'
' Refresh Query
With ActiveWorkbook.Connections("Connection").OLEDBConnection
.CommandText = queryStr
.Refresh
End With
End Sub
Is there a way for the user to manually cancel the query (calling .CancelRefresh) while the Excel user-interface is frozen?
EDIT I don't know if the following is worth noting or regular behavior. While the query is executing, all open Excel windows (including the VBA Editor) become "Not Responding" in Task Manager. Neither pressing Esc nor Ctrl+Break will cancel the script. Also, calling DoEvents (either before or after .Refresh) does not change this behavior.
Here's a method that I know will work. However, there are some complications.
Here's how it's done:
Put the spreadsheet with the data in a separate workbook. This worksheet should execute the refresh query when it's opened and then close once the data is updated.
Create a batch file to call the "Data" Excel file.
Within a different workbook, create a procedure (macro) for the user to call. This procedure will call the batch file, which subsequently calls the Excel file. Since you are calling a batch file and not Excel directly, the Excel procedure will continue because the command shell is released so quickly and opens the other Excel file in a different thread. This allows you to continue working within the main Excel file.
Here are some complications:
I included a method to alert the user that the data has been udpated. There are timing issues where it's possible to try to check if the data has been update when the workbook is not accessible, which forces the user to try to update values. I included a method called my time which pauses the execution of the code so it only checks every so many seconds.
The updated worksheet will pop up in a new window, so the user will need to click on their original worksheet and keep working. You could learn to hide this if you're comfortable with Windows scripting (I haven't learned that yet).
Here are some files and code. Be sure to read the comments in the code for why some things are there.
FILE: C:\DataUpdate.xls
We'll make a workbook called "DataUpdate.xls" and put it in our C:\ folder. In cell A1 of Sheet1, we'll add our QueryTable which grabs external data.
Option Explicit
Sub UpdateTable()
Dim ws As Worksheet
Dim qt As QueryTable
Set ws = Worksheets("Sheet1")
Set qt = ws.Range("A1").QueryTable
qt.Refresh BackgroundQuery:=False
End Sub
Sub OnWorkbookOpen()
Dim wb As Workbook
Set wb = ActiveWorkbook
'I put this If statement in so I can change the file's
'name and then edit the file without code
'running. You may find a better way to do this.
If ActiveWorkbook.Name = "DataUpdate.xls" Then
UpdateTable
'I update a cell in a different sheet once the update is completed.
'I'll check this cell from the "user workbook" to see when the data's been updated.
Sheets("Sheet2").Range("A1").Value = "Update Table Completed " & Now()
wb.Save
Application.Quit
End If
End Sub
In the ThisWorkbook object in Excel, there's a procedure called Workbook_Open(). It should look like the following so it executes the update code when it is opened.
Private Sub Workbook_Open()
OnWorkbookOpen
End Sub
NOTE: I found a bug when this file closed if 1) you accessed the file from the command line or shell and 2) you have the Office Live Add-in installed. If you have the Office Live Add-in installed, it will throw an exception on exit.
FILE: C:\RunExcel.bat
Next, we're going to create a batch file that will open the Excel file we just made. The reason that call the Excel file from within the batch file and not directly from the other Excel file using Shell is because Shell will not continue until the other application closes (at least when using Excel.exe "c:\File.xls"). The batch file, however, runs its code and then immediately closes, thus allowing the original code that called it to continue. This is what will let your uses continue working in Excel.
All this file needs is:
cd "C:\Program Files\Microsoft Office\Office10\"
Excel.exe "C:\DataUpdate.xls"
If you're handy with Windows Scripting, you do fancy things like open the window in a hidden mode or pass a parameter of the file name or Excel location. I kept it simple with a batch file.
FILE: C:\UserWorkbook.xls
This is the file that the user will open to "do their work in." They'll call the code to update the other workbook from within this workbook and they'll still be able to work in this workbook while this one is updating.
You need a cell in this workbook where you'll check the "Update Table Completed" cell from the DataUpdate workbook. I chose cell G1 in Sheet1 for my example.
Add the following code to a VBA module in this workbook:
Option Explicit
Sub UpdateOtherWorkbook()
Dim strFilePath As String
Dim intOpenMode As Integer
Dim strCallPath As String
Dim strCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
'This makes sure the formula has the most recent "Updated" value
'from the data file.
rng.Formula = strCellFormula
strFilePath = "C:\RunExcel.bat"
intOpenMode = vbHide
'This will call the batch file that calls the Excel file.
'Since the batch file executes it's code and then closes,
'the Excel file will be able to keep running.
Shell strFilePath, intOpenMode
'This method, defined below, will alert the user with a
'message box once the update is complete. We know that
'the update is complete because the "Updated" value will
'have changed in the Data workbook.
AlertWhenChanged
End Sub
'
Sub AlertWhenChanged()
Dim strCellValue As String
Dim strUpdatedCellValue As String
Dim strCellFormula As String
Dim ws As Worksheet
Dim rng As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("G1")
strCellFormula = "='C:\[DataUpdate.xls]Sheet2'!A1"
strCellValue = rng.Value
strUpdatedCellValue = strCellValue
'This will check every 4 seconds to see if the Update value of the
'Data workbook has been changed. MyWait is included to make sure
'we don't try to access the Data file while it is inaccessible.
'During this entire process, the user is still able to work.
Do While strCellValue = strUpdatedCellValue
MyWait 2
rng.Formula = strCellFormula
MyWait 2
strUpdatedCellValue = rng.Value
DoEvents
Loop
MsgBox "Data Has Been Updated!"
End Sub
'
Sub MyWait(lngSeconds As Long)
Dim dtmNewTime As Date
dtmNewTime = DateAdd("s", lngSeconds, Now)
Do While Now < dtmNewTime
DoEvents
Loop
End Sub
As you can see, I constantly updated the formula in the "Listening Cell" to see when the other cell was updated. Once the data workbook has been updated, I'm not sure how you'd force an update in code without rewriting all the cells. Closing the workbook and reopening it should refresh the values, but I'm not sure of the best way to do it in code.
This whole process works because you're using a batch file to call Excel into a different thread from the original file. This allows you to work in the original file and still be alerted when the other file has been updated.
Good luck!
EDIT: Rather than include a more complete answer in this same answer, I've created a separate answer dedicated entirely to that solution. Check it out below (or above if it gets voted up)
Your users can break the VBA function by pressing Ctrl+Break on the keyboard. However, I've found that this can cause your functions to randomly break until each time any function is run. It goes away when the computer is restarted.
If you open this file in a new instance of Excel (meaning, go to Start > Programs and open Excel from there), I think that the only workbook that will be frozen will be the one executing the code. Other intances of Excel shouldn't be affected.
Lastly, you might research the DoEvents functions, which yields execution back to the Operating System so that it can process other events. I'm not sure if it would work in your case, but you could look into it. That way you can do other things while the process is being completed (It's kind of dangerous because the user can then change the state of your application while the process is working).
I believe I know a way that actually will work, but it's complicated and I don't have the code in front of me. It involves creating a separate instance of the Excel application in code and attaching a handler to the execution of that instance. You include the DoEvents part of the code in a loop that releases once the application closes. The other instantiated Excel application has the sole purpose of opening a file to execute a script and then close itself. I've done something like this before so I know that it works. I'll see if I can find the code tomorrow and add it.
Well, you could consider the old-fashion way -- split the query into smaller batches and use Do Events in between batches.
You could try XLLoop. This lets you write excel functions (UDfs) on an external server. It includes server implementations in many languages (eg. Java, Ruby, Python, PHP).
You could then connect to your oracle database (and potentially add a caching layer) and serve up the data to your spreadsheet that way.
The XLL also has a feature to popup a "busy" GUI that lets the user cancel the function call (which disconnects from the server).
BTW, I work on the project so let me know if you have any questions.