I'm trying to improve performance of my Oracle SQL queries by using array binding to an OracleParameter.
This is basically what I'm trying to do:
List<string> IDValList = new List<string>();
IDValList.Add( "IDOne" );
IDValList.Add( "IDTwo" );
List<int> sizes = new List<int>();
foreach( string id in IDValList )
{
sizes.Add( id.Length );
}
using( OracleCommand cmd = new OracleCommand( "select col1, col2, col3 from table where col4 in ( :idArray )", _conn ) )
{
cmd.CommandType = System.Data.CommandType.Text;
OracleParameter arrayParam = new OracleParameter( "idArray", OracleDbType.Varchar2 );
arrayParam.Direction = System.Data.ParameterDirection.Input;
arrayParam.Value = IDValList.ToArray();
arrayParam.ArrayBindSize = sizes.ToArray();
cmd.ArrayBindCount = IDValList.Count;
cmd.Parameters.Add( arrayParam );
using( OracleDataReader dr = cmd.ExecuteReader() )
{
while( dr.Read() )
{
// now read the row...
This compiles and runs, but I always only get back one row, for the first ID. Its like its ignoring the rest of the values in the array in the parameter.
Interestingly enough, the ArrayBindStatus of the parameter is successful for all the values.
What am I missing? Or will this not work with an OracleReader?
Thanks
Edit: Basically, I'm trying to follow this example, but I want to be able to read the resulting dataset from the query using a DataReader.
http://www.oracle.com/technology/oramag/oracle/09-sep/o59odpnet.html
There are several ways of doing the "variable in list" that you are searching for. To utilize a bound parameter.
This is based on this: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:210612357425
frankly I try to use bind variables as often as possible if not just for the performance increase, but for the additional level of security.
while there are many ways to skin a cat, this (while verbose) ought to do it
in Oracle --create your type create or replace type varcharTableType as table of varchar2 (255);
--create your function
function in_varchar( p_string in varchar2 ) return varcharTableType
as
l_string long default p_string || ',';
l_data varcharTableType := varcharTableType();
n number;
begin
loop
exit when l_string is null;
n := instr( l_string, ',' );
l_data.extend;
l_data(l_data.count) :=
ltrim( rtrim( substr( l_string, 1, n-1 ) ) );
l_string := substr( l_string, n+1 );
end loop;
RETURN L_DATA;
END in_varchar;
now ammend your query in .net
col4 in ( select COLUMN_VALUE from table(in_varchar(:idArray )) )
(btw I copied most of this code from a previous posting I answered on oracle forums: http://forums.oracle.com/forums/thread.jspa?messageID=4299793�
this would actually make it so you wouldn't have to use the array binding, just make sure that is a comma delimited string: :idArray = "A,B,C"
Another option is to return the select statements into a ref cursor array:
/* example table
*
Create Table Zzztab(Deptno Number, Deptname Varchar2(50) , Loc Varchar2(50) , State Varchar2(2) , Idno Number(10)) ;
/
insert into Zzztab(Deptno , Deptname , Loc , State , Idno)
values (0,'Zero','US','NY',0);
insert into Zzztab(Deptno , Deptname , Loc , State , Idno)
values (1,'One','CA','ON',1);
insert into Zzztab(Deptno , Deptname , Loc , State , Idno)
values (2,'Three','IS',null,2);
insert into Zzztab(Deptno , Deptname , Loc , State , Idno)
values (3,'Four','BD',null,3);
*/
string connectStr = GetConnectionString();
// Initialize array of data
String[] myArrayDeptName = { "Zero", "Three", "Four" };
OracleConnection connection = new OracleConnection(connectStr);
OracleCommand command = new OracleCommand();
command.Connection = connection;
command.CommandType = CommandType.Text ;
command.CommandText = "begin open :cur for SELECT DEPTNO, DEPTNAME FROM ZZZTAB WHERE DEPTNAME = :DEPT; end;";
command.ArrayBindCount = myArrayDeptName.Length ;
command.BindByName = true;
OracleParameter cur = new OracleParameter("cur", OracleDbType.RefCursor );
cur.Direction = ParameterDirection.Output;
cur.Value = myArrayDeptName;
command.Parameters.Add(cur);
// deptname parameter
OracleParameter deptNameParam = new OracleParameter("DEPT", OracleDbType.Varchar2);
deptNameParam.Direction = ParameterDirection.Input;
deptNameParam.Value = myArrayDeptName;
command.Parameters.Add(deptNameParam);
try
{
connection.Open();
command.ExecuteNonQuery();
foreach (Oracle.DataAccess.Types.OracleRefCursor rc in (Oracle.DataAccess.Types.OracleRefCursor[])cur.Value)
{ ... fill in an join the datatables
you can use the exact same logic and just have the columns return into each their own array.