Skip to Main Content
  • Questions
  • How do I use bind variables with ODBC?

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Kevin.

Asked: February 24, 2003 - 3:13 pm UTC

Last updated: December 08, 2004 - 11:15 am UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

I realize you may not address VB and ODBC issues, but I was trying to see if there was a way to use bind variables in an ODBC connection from an Excel spreadsheet through VB to an Oracle database. I've been reading the discussions you had in some of the threads and thought it might be advantages to not have to reparse complex queries, some of which are more complicated than listed below. I've already realized a 10 times increase in performance having Oracle calculate these statistics instead of the spreadsheet or VB, and thought I'd try to help the database by not making it have to reparse these nasty things.

If I knew how to change the station variable to a bind variable and pass it to the ODBC, I'd be in great shape, but I can't find a source of information describing how to do this.


Private Sub StatisticsButton_Click()
Dim conn_str As String
Dim sql_str As String
Dim station As String


'set the sql connection string
conn_str = "ODBC;DSN=DEVL;UID=PUB;PWD=PUB;DBQ=DEVL;ASY=OFF;"

sql_str = ""
sql_str = "SELECT POWER(CORR(a.value, TO_NUMBER(DECODE(b.value,-999,NULL,-902,NULL,-901,NULL,b.value))), 2) AS "R-squared", "
sql_str = sql_str & " POWER( SUM( POWER( (a.value - TO_NUMBER(DECODE(b.value,-999,NULL,-902,NULL,-901,NULL,b.value) ) ),2)) / "
sql_str = sql_str & " (COUNT(b.value)-1),.5) AS RMSE, "
sql_str = sql_str & " SUM(a.value - TO_NUMBER(DECODE(b.value,-999,NULL,-902,NULL,-901,NULL, b.value)))/count(b.value) AS BIAS, "
sql_str = sql_str & " (SUM(POWER( (a.value - (SELECT AVG(z.value) FROM dm_daily_data z WHERE z.dbkey = a.dbkey)),2)) - "
sql_str = sql_str & " SUM(POWER( (TO_NUMBER(decode(b.value,-999,NULL, -902,NULL, -901,NULL, b.value))-a.value),2)))/ "
sql_str = sql_str & " SUM(POWER( (a.value - (SELECT AVG(z.value) FROM dm_daily_data z WHERE z.dbkey = a.dbkey)),2)) AS Efficiency, "
sql_str = sql_str & " COUNT(b.value) AS BCOUNT "
sql_str = sql_str & " FROM dm_daily_data a, "
sql_str = sql_str & " hsm_weekly_data b, "
sql_str = sql_str & " hsm_stations c "
sql_str = sql_str & " WHERE a.dbkey = c.dbkey "
sql_str = sql_str & " AND c.hsm = b.hsm_station "
sql_str = sql_str & " AND a.daily_date = b.weekly_date "
sql_str = sql_str & " AND b.hsm_station = '" & station & "' "
sql_str = sql_str & " AND a.value IS NOT NULL "
sql_str = sql_str & " AND TO_NUMBER(DECODE(b.value,-999,NULL, -902,NULL, -901,NULL,b.value)) IS NOT NULL"

With ActiveSheet.QueryTables.Add(Connection:=conn_str, Destination:=ActiveSheet.Range("AF3"), Sql:=sql_str)
.RefreshStyle = xlOverwriteCells
.Refresh
End With

End Sub

and Tom said...

Tell you what -- I'll publish this and hopefully a VB programmer will give a better answer.


Quick fix for you, add a statement:

alter session set cursor_sharing=force;
run query
alter session set cursor_sharing=exact;


that'll "autobind" for you.

But -- hopefully a VB programmer can help us out here.

Rating

  (15 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

ODBC and ADO support parameters for queries

Mike, February 25, 2003 - 10:50 am UTC

I've worked in both VB and Delphi with ODBC and ADO.
There are query objects for retrieving datasets or
sending commands to the database. Both contain mechnisms
for "parameterization" of queries. Usually this takes
the form of:

MYQUERY.PARAMETER[ 'XYZ' ] := MYVALUE

The actual SQL looks like:

SELECT * FROM MYTABLE WHERE MYCOLUMN = :XYZ

Hope this helps.

Avoid Extra Parsing

Kevin Perez, February 25, 2003 - 12:48 pm UTC

Don't forget that if your program will be issuing this call numerous times, you should keep the cursor open to avoid extra soft parses.

I know this isn't directly related to Binding Variable question but it is related enough that it should be kept in mind when creating these VB and/or Delphi procedures.

Thanks Tom ;)


Not sure

Alex, February 25, 2003 - 4:10 pm UTC

Kevin,

I am not sure that this will help . ( I am not VB dev myself ). There is a note on Metalink with title "Using Bind variables with RDO, ODBC in SQL Statements". The note id is: 111845.1.



ME?!?

Not the other Kevin, February 26, 2003 - 2:00 pm UTC

Shouldn't have that been directed to ummm, the other Kevin?
;)


Multi-disciplined Database Programmers

Kevin Rodberg, February 27, 2003 - 11:32 am UTC

Thank you all for the comments and suggestions. The MetaLink note 111845.1 was exactly what I was looking for. I'll still look into how you keep the cursor open since I'm not sure how this works with ODBC.

It's nice to be able to post a request for information and get assistance form such a diverse group of backgrounds, with a common area of interest.


Who develop ODBC for Oracle?

TH, September 14, 2003 - 8:42 am UTC

I'm sure Oracle is Developing ODBC to connect to Oracle. Does third pary also develop ODBC for Oracle? (I heared some native ODBC drivers related to Delphi.)

Thanx,
Thaha

Tom Kyte
September 14, 2003 - 10:02 am UTC

yes, many people have made odbc adapters.

Oracle Best Practices (VB/VBA)

Mike Wilson, September 14, 2003 - 4:28 pm UTC

I do a lot of VB/VBA development (and I'm a DBA, weird isn't it?).

A few thoughts:
1) Don't use ODBC!
Use ADO instead, it's faster (uses OLE DB, circumventing the Jet layer), has better error handling (Errors collection), allows for disconnected recordsets, and client side cursors. Did mention it's way faster? It will require you to download the latest MDAC from MS. I recommend MDAC 2.7 RTM.

2) Don't embed SQL in your VB code.
It's messy, hard to maintain, and a royal pain to debug. It's much "cleaner" if you seperate your SQL into a view on the database side. You can embed the query during development but I *highly* recommend you move it to a view once you get the recordset you require. Work with your DBA on this. If you *must* code a query into your VB code then move the complex query into a view and reference it as "select * from my_view where fld = ?".

3) Use bind variables wherever possible.
If you can't use bind variables easily (you probably shouldn't be doing what you are doing) then consider calling out through ADO and "alter session set cursor_sharing=force". See below for an simple example of using a bind variable with ADO. Note, Excel will only use a ODBC query for External Data Tables.

4) Use the ADODB.Errors collection for error handling.
Every VB routine that references the DB should use the ADODB.Errors collection. No funtion/sub is too small to avoid this.

5) Have Oracle calculate as much as possible.
It's far more efficient at handling large datasets and almost any function you can think of in Excel can probably be coded as a PL/SQL function or field in a view. Again, work with your DBA on this. You can flesh out your query locally but it will be much faster in the DB. This will be particularly true in the upcomming 10g with it's new MODEL clause. {nifty examples BTW Tom at OracleWorld}

6) Use BeginTrans and EndTrans to batch update.
Where possible use the BeginTrans and Commit/Rollback methods of the Connection object when updating large #'s of records. It's *much* faster than commiting on every change. You can also use the UpdateBatch method of the Recordset object. Again, this is ADO, not ODBC.

7) Let Excel to it for you.
Excel can handle your parameters natively without needing to code all of this up like you have done. None of the code you have shown is required if you simply wish to generate a filtered table in Excel.

Here's how I do it:
a) Move your query into a view in Oracle. Let it return all of the data. You will filter when you build the query or with AutoFiltering in Excel.
b) Insert the view in a worksheet (Tools/External Data) and in the Query Builder create your filter such that "fld = [my_param1]" (use the brackets to indicate a query parameter).
b) Return the data to Excel. When the query runs you will be asked to provide values for the parameters that have [] around them. This will allow Oracle to filter your view.
c) Once you get the data into Excel, if you right-click on the table you can use the Parameters... option to set the values a) for all time, b) for one run, or c) referencing a set of cells in your spreadsheet.

I use this technique to help track ticket assignments in our Helpdesk system in a spreadsheet. It allows them to type their name in as the ASSIGNED cell of the workbook, which Excel uses as a parameter for the table. I also set the table to auto-update every 15 minutes. To ease load I created this as a Materialized View also. This is the best of all worlds, speed, filtering, and views from Oracle, ease of use from Excel.

Hope this helps.

Mike


Sub ParameterExample()
Dim cmd As New ADODB.Command
Dim rs As New ADODB.Recordset
Dim prm As ADODB.Parameter

' Set the command's connection using a connection string.
cmd.ActiveConnection = Provider=OraOLEDB.Oracle;User ID=scott;Password=tiger;Data Source=oraDSN;
' Set the command's text, and specify that it
' is an SQL statement.
cmd.CommandText = "Select empno from emp where deptno = ?"
cmd.CommandType = adCmdText

' Set up a new parameter for the stored procedure.
Set prm = cmd.CreateParameter("deptno", adInteger, adParamInput, , 10)
cmd.Parameters.Append prm

' Create a recordset by executing the command.
Set rs = cmd.Execute

' Loop through the recordset and print the first field.
Do While Not rs.EOF
Debug.Print rs(0)
rs.MoveNext
Loop

' Close the recordset.
rs.Close

End Sub

Oracle Overview of OleDB (with Code Samples):
</code> http://download-west.oracle.com/docs/cd/B10501_01/win.920/a95498/intro.htm

Good Overview of MS Data Technologies:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsqlmag02/html/TheEvolutionofData-AccessTechnologies.asp <code>

Tom Kyte
September 14, 2003 - 10:13 pm UTC

thanks, really appreciate that.

gotta love #3! :)

Use oo4o

Jim Kennedy, September 14, 2003 - 11:42 pm UTC

I use Oracle's Ole Objects. Very fast, nice parameter interface, supports all the Oracle datatypes. It is especially nice to define your queries with parameters as globals and just do a refresh and execute on the query. eg

create the parameter x
create dynaset with parameter x
at a later time set the value of the parameter x.value = ...
dyneset.refresh.
Very fast. Also it has a nice array interface (on a particular system took 2.5 seconds to insert 30,000 rows in a small narrow table)




OO4O - my 2 cents

robert, September 15, 2003 - 11:13 am UTC

Yes, OO4O on client and plsql on Oracle --- I have yet to
have hear arguments that this is not the most efficient & flexible way of doing VB/Oracle programming.

ADO ? --- much ADO about nothing....it's unfortunate enough
that one is tied down to VB/Windoz, why thro in another bucket of @#$% ?

Have VB do as little as possible --- just gather parameters & pass on to Oracle in the form of stored procedure call.

Tatiane

Tatiane, September 18, 2003 - 9:24 am UTC

Tom, you said:

>alter session set cursor_sharing=force;
>run query
>alter session set cursor_sharing=exact;

1) I know how cursor_sharing works, but what exactly was your intention here ?

2) Any caveats to using cursor_sharing=safe, instead of force ?

Tom Kyte
September 18, 2003 - 10:46 am UTC

1) to get bind variables into their system....

2) safe? do you mean similar? similar was added in 9i, didn't exist at the release they are using. similar can be used, yes.

cursor_sharing

Tatiane, September 18, 2003 - 11:04 am UTC

Tom, continuing from above...

>to get bind variables into their system

... it's obvious, I know

But why didn't you simply set it to force, instead of setting to force, running the query and then setting to exact ? What is the reasoning behind that ?

What I would normally do:

o alter system set cursor_sharing=force (or similar)
o alter system flush shared_pool (so there won't be old statements with literals in the shared pool)
o let them system run

Tom Kyte
September 18, 2003 - 11:15 am UTC



i don't like setting to force for the entire session. it could have side effects elsewhere.

i want them to FIX the code, not bandage it. cursor sharing is a big bandaid to me, i don't like it.

Side effects

Tatiane, September 18, 2003 - 1:25 pm UTC

I agree cursor_sharing is a band-aid.

What kind of side-effects ?

The only one I am aware of is additional soft-parse overhead...

Can you point me to some discussion on it ? I was looking for it but I could not find.

Thanks

Tom Kyte
September 18, 2003 - 2:42 pm UTC

chapter 10 in my book "Expert one on one Oracle" has a discussion.

it can change query plans (for the better or worse -- bottom line is "things can change")

it will change the returned default widths of many columns. your query that was:

select ..., substr( x, 1, 5 ) x from t

was KNOWN to return a varchar2(5). Now it is:

select ..., substr( x, :sys_bv_0, :sys_bv_1 ) x from t;

it is no longer KNOWN what width that will be. can you imagine the havoc that might play with a report generator?? all of a sudden the stuff that printed just dandy yesterday won't fit on the page -- even in landscape mode...



No to OO4O/ODBC/ADO yes to www

Johan Snyman, September 19, 2003 - 6:51 am UTC

I recently solved this kind of problem by using a PL/SQL package to generate the required results in html format via the web sql toolkit and mod_plsql.

Then you use Excel's web query facility to access the appropriate URL's and supply the appropriate parameters (either prompted or taken from a spreadsheet cell or from a spreadsheet cell populated from a VBA drop down list, with a range of cells that are auto-updated via webquery from the Oracle database when the spreadsheet is opened as the date source).

This way all the user require is MS Excel and network access to the Oracle HTTP server. No client side install (you can even have them download the spreadsheet from the web site). No oracle net client software to install and configure. No ODBC driver installation and setup. No OO4O install and setup. Very similar to a purely browser based approach.

The only downside is some additional soft parsing, due to the statelessness among calls, but the pros far outweigh the cons. It is like using Excel as a slightly more sophisticated web browser (in this case it was mostly done in order to enable use of Excel's extensive charting capabilities, and to allow users to easily analyse the data in an environment they are already familiar with.)

cursor sharing

Douglas, September 19, 2003 - 9:34 am UTC

Guys, I have used cursor_sharing=force for quite a while now ( 2+ years ) and have never found any problems with it.
I have only had benefits ! My soft parse ratios are always cool and I have never noticed any side effects.

Tom Kyte
September 20, 2003 - 5:31 pm UTC



you still have a bug in your code that needs to be fixed.

your parse to execute ratio should be improved as well -- you are parsing more then you should.

it does have side effects
you do need to fully test a system before just flinging it on.

ODBC Drivers for Oracle

Ravi Thapliyal, December 08, 2004 - 11:15 am UTC

It was a nice reading