TelMaco
asked on
Run Oracle query using Excel VBA
Bit of background first:
I have 3 Oracle queries that need to be populated into an Excel file. My IT department set-up a website where I can enter an Oracle query and it will display the results of my query on the web page.
I have a VBA macro which navigates to the page, enters the query, and copies the results back into Excel. This website will not be supported for very long, and I need another solution.
So here's what I'm trying to figure out:
I want to use VBA to connect to the Oracle database, run the queries, and return the results into my Excel file. I want to use VBA code to replace the function of the website. Ideally, I'd also like to learn how to format a report based on the results - all within VBA...but I think I'll start a new question worth separate points for that, so I'll take this one step at a time.
How can I go about this? The idea of using VBA to run the query is really new to me, and I've never done anything like it.
Thank you!
I have 3 Oracle queries that need to be populated into an Excel file. My IT department set-up a website where I can enter an Oracle query and it will display the results of my query on the web page.
I have a VBA macro which navigates to the page, enters the query, and copies the results back into Excel. This website will not be supported for very long, and I need another solution.
So here's what I'm trying to figure out:
I want to use VBA to connect to the Oracle database, run the queries, and return the results into my Excel file. I want to use VBA code to replace the function of the website. Ideally, I'd also like to learn how to format a report based on the results - all within VBA...but I think I'll start a new question worth separate points for that, so I'll take this one step at a time.
How can I go about this? The idea of using VBA to run the query is really new to me, and I've never done anything like it.
Thank you!
Columns A-D are filled in with the first four values returned from Oracle. Column E, in this case, fills in with a value determined by the combined contents of the fifth and sixth columns (indexes 4 and 5 in a zero-based array). Of course, your SQL can be much more elaborate than "SELECT * FROM ..." so you can specify exactly what will be where in your returned recordset.
This code also breaks the returned data into groups of 65,000 rows, because Excel has a limit of 65535 (or is it 65536?) rows on a single sheet. So if you're returning more data than 65,000 rows, the macro will continue to add new sheets for you as it goes.
I see, now, that I missed a snippet, though. After the Loop and before the End Sub, you should insert these three lines:
This code also breaks the returned data into groups of 65,000 rows, because Excel has a limit of 65535 (or is it 65536?) rows on a single sheet. So if you're returning more data than 65,000 rows, the macro will continue to add new sheets for you as it goes.
I see, now, that I missed a snippet, though. After the Loop and before the End Sub, you should insert these three lines:
oConOracle.Close
Set oRsOracle = Nothing
Set oConOracle = Nothing
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I have Oracle installed...I do not see that driver under references though. Would I need to use the browse option to look in the actual Oracle folders? If so, there are a dozen of those *.dll files...specifically what do I need to add as a reference.
Thanks!
Thanks!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ok option #1 is working, I'll take a look at what Leon suggested in a moment. Although it may have to wait until the morning.
Thanks!
Thanks!
I love this place.
I do my best to figure out how to do things (often using EE as a primary resource) and cobble together things that work, and I'm happy to share what I know because so many here have helped me. And even when I come in and provide a working solution, someone else can still come in and improve on it, which means now my own things will be faster and better the next time I need to do this.
Thanks, leonstryker!
I do my best to figure out how to do things (often using EE as a primary resource) and cobble together things that work, and I'm happy to share what I know because so many here have helped me. And even when I come in and provide a working solution, someone else can still come in and improve on it, which means now my own things will be faster and better the next time I need to do this.
Thanks, leonstryker!
Why do you need a VBA to pull data from Excel ?
You can create a ODBC connection.
Go to excel. Menu->Data->Import External Data
Select ODBC from file type and the correct source.
Write the query.
The data will be pulled into the active sheet.
You can refresh the data every time by right click on any one of the cells containing data and refresh.
This will become your local copy of the data file.
You can write macros to create report or change format.
(You will have GUI interface in MS-Query to edit the query fields. This will save time in writing exact code)
You can create a ODBC connection.
Go to excel. Menu->Data->Import External Data
Select ODBC from file type and the correct source.
Write the query.
The data will be pulled into the active sheet.
You can refresh the data every time by right click on any one of the cells containing data and refresh.
This will become your local copy of the data file.
You can write macros to create report or change format.
(You will have GUI interface in MS-Query to edit the query fields. This will save time in writing exact code)
>Why do you need a VBA to pull data from Excel ?
There are lots of reasons to do it this way as opposed to using MS-Query among them are:
1. Its more stable (no persistant connection and separation of code from data.)
2. Its versitale (can switch databases quickly, use multiple datasources, as well as use complex store procedures to query data)
3. You can dump the results into separate files to be used as reports
4. etc.
Leon
There are lots of reasons to do it this way as opposed to using MS-Query among them are:
1. Its more stable (no persistant connection and separation of code from data.)
2. Its versitale (can switch databases quickly, use multiple datasources, as well as use complex store procedures to query data)
3. You can dump the results into separate files to be used as reports
4. etc.
Leon
ASKER
Good question, I used to do this via Import External Data, and it pulled from existing MS access queries. Worked fine, until I put it on a server, and had someone else update the file.
For someone else to run it they needed to have their Oracle tnsnames.ora and personal.ora Txt files set-up properly, and an ODBC connection set-up under Data Sources.
When my IT guys set up the website to run Oracle queries on, it bypasses the need to have all that set-up on the users PC. As long as they have Oracle installed they could use the web site. Or rather, VBA could use the website from their computer and import the web queries into Excel.
As the website is going to disapear soon, I needed another way, hence, running the entire query in VBA. It'll still require the user has Oracle, but I don't need to get on each users computer and change the *.ora files and such.
Leon, I'm sorry for taking so long to try your suggestion. I'm out of the office today, and running this stuff off VPN is terribly slow. I'll try to look on Thursday, if not, I'm gone until Monday.
I won't abandon the post, and promise to update as soon as I get a chance to test further.
Thanks for your help!
For someone else to run it they needed to have their Oracle tnsnames.ora and personal.ora Txt files set-up properly, and an ODBC connection set-up under Data Sources.
When my IT guys set up the website to run Oracle queries on, it bypasses the need to have all that set-up on the users PC. As long as they have Oracle installed they could use the web site. Or rather, VBA could use the website from their computer and import the web queries into Excel.
As the website is going to disapear soon, I needed another way, hence, running the entire query in VBA. It'll still require the user has Oracle, but I don't need to get on each users computer and change the *.ora files and such.
Leon, I'm sorry for taking so long to try your suggestion. I'm out of the office today, and running this stuff off VPN is terribly slow. I'll try to look on Thursday, if not, I'm gone until Monday.
I won't abandon the post, and promise to update as soon as I get a chance to test further.
Thanks for your help!
ASKER
Much faster with the CopyFromRecordSet method. Thank you!
I don't understand Late vs Early binding. What's the difference?
I've included the VBA that's working, if you'd care to show how to mod it to be early binding, and explain the benifit?
Thanks everyone!
I don't understand Late vs Early binding. What's the difference?
I've included the VBA that's working, if you'd care to show how to mod it to be early binding, and explain the benifit?
Thanks everyone!
Sub HarvestData()
'On Error Resume Next
' Makes the SQL call to collect the data.
Dim strConOracle As String
Dim oConOracle, oRsOracle
Dim strSQL As String
Dim lngCount As Long
Dim strCount As String
Dim x As String
x = Sheets("Sheet4").Range("T1")
strConOracle = "Driver={Microsoft ODBC for Oracle}; CONNECTSTRING=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)"
strConOracle = strConOracle & "(HOST=" & HOST & ")(PORT=57699))(CONNECT_DATA=(SERVICE_NAME=" & DBNAME
strConOracle = strConOracle & "))); uid=" & ORACLE_USER_NAME & " ;pwd=" & ORACLE_PASSWORD & ";"
Set oConOracle = CreateObject("ADODB.Connection")
Set oRsOracle = CreateObject("ADODB.RecordSet")
oConOracle.Open strConOracle
strSQL = x
Set oRsOracle = oConOracle.Execute(strSQL)
ActiveSheet.Cells.CopyFromRecordset oRsOracle
oConOracle.Close
Set oRsOracle = Nothing
Set oConOracle = Nothing
End Sub
The code I provided (that you have, above) uses this:
Dim oConOracle, oRsOracle
Set oConOracle = CreateObject("ADODB.Connec tion")
Set oRsOracle = CreateObject("ADODB.Record Set")
oConOracle.Open strConOracle
That's "late binding," because oConOracle and oRsOracle are declared as variants and VB doesn't know what to do with them until later, when they actually have an object assigned.
leonstryker suggested this code instead:
Dim oConOracle As ADODB.Connection
Dim oRsOracle As ADODB.Recordset
Set oConOracle = New ADODB.Connection
Set oRsOracle = New ADODB.Recordset
From the outset, VB knows exactly what oConOracle and oRsOracle are and how to treat them. The nature of their structure is bound to the variable names immediately on declaration. This results in less internal overhead later any time it actually has to reference the objects or do anything with them.
From a practical standpoint, with this relatively small amount of code the differences in performance or resource utilization would be negligible. But in a larger project, all the little bits do add up. In situations where it is an option, early binding is considered good practice. leonstryker's suggestion is a good one.
-- b.r.t.
Dim oConOracle, oRsOracle
Set oConOracle = CreateObject("ADODB.Connec
Set oRsOracle = CreateObject("ADODB.Record
oConOracle.Open strConOracle
That's "late binding," because oConOracle and oRsOracle are declared as variants and VB doesn't know what to do with them until later, when they actually have an object assigned.
leonstryker suggested this code instead:
Dim oConOracle As ADODB.Connection
Dim oRsOracle As ADODB.Recordset
Set oConOracle = New ADODB.Connection
Set oRsOracle = New ADODB.Recordset
From the outset, VB knows exactly what oConOracle and oRsOracle are and how to treat them. The nature of their structure is bound to the variable names immediately on declaration. This results in less internal overhead later any time it actually has to reference the objects or do anything with them.
From a practical standpoint, with this relatively small amount of code the differences in performance or resource utilization would be negligible. But in a larger project, all the little bits do add up. In situations where it is an option, early binding is considered good practice. leonstryker's suggestion is a good one.
-- b.r.t.
In additon, using Early Binding will help with syntax since the Intellisense will work (will show you the methods and properties).
The down side of Early Binding is that it is less portable and relies that all client machines use the same version of the DLL which you are referencing, while Late Binding generally does not care as long as the methods you are using are present.
Thanks for the grade,
Leon
The down side of Early Binding is that it is less portable and relies that all client machines use the same version of the DLL which you are referencing, while Late Binding generally does not care as long as the methods you are using are present.
Thanks for the grade,
Leon
In order to run it, you have to have the Oracle ODBC driver installed on your PC (it's installed if you have Oracle installed), and you have to go to Tools -> References in the VB editor and add the reference to the driver.
Open in new window