Vanaf de SQL-kant zou je een tabeltype kunnen definiëren en dat gebruiken om je echte gegevens aan te sluiten, zoiets als:
create type my_array_type as table of number
/
create or replace function f42 (in_array my_array_type)
return sys_refcursor as
rc sys_refcursor;
begin
open rc for
select a.column_value as id,
case when t.id is null then 'missing'
else 'present' end as status
from table(in_array) a
left join t42 t on t.id = a.column_value
order by id;
return rc;
end f42;
/
SQL Fiddle-demo met een wrapper-functie zodat u deze direct kunt opvragen, wat het volgende geeft:
ID STATUS
---------- --------------------
1 present
2 present
3 present
4 missing
8 missing
23 present
Vanuit Java kunt u een ARRAY
. definiëren vul op basis van het tabeltype in vanuit een Java-array en roep de functie rechtstreeks aan; uw enkele parameter bindvariabele is de ARRAY
, en je krijgt een resultatenset terug die je normaal kunt herhalen.
Als een schets van de Java-kant:
int[] ids = { 1, 2, 3, 4, 8, 23 };
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("MY_ARRAY_TYPE",
conn);
oracle.sql.ARRAY ora_ids = new oracle.sql.ARRAY(aDesc, conn, ids);
cStmt = (OracleCallableStatement) conn.prepareCall("{ call ? := f42(?) }");
cStmt.registerOutParameter(1, OracleTypes.CURSOR);
cStmt.setArray(2, ora_ids);
cStmt.execute();
rSet = (OracleResultSet) cStmt.getCursor(1);
while (rSet.next())
{
System.out.println("id " + rSet.getInt(1) + ": " + rSet.getString(2));
}
Wat geeft:
id 1: present
id 2: present
id 3: present
id 4: missing
id 8: missing
id 23: present
Zoals Maheswaran Ravisankar vermeldt, kan hierdoor een willekeurig aantal elementen worden doorgegeven; je hoeft niet te weten hoeveel elementen er zijn tijdens het compileren (of te maken hebben met een theoretisch maximum), je bent niet beperkt door het maximum aantal toegestane expressies in een IN
of door de lengte van een enkele gescheiden tekenreeks, en u hoeft een tekenreeks niet samen te stellen en te ontleden om meerdere waarden door te geven.
Zoals ThinkJet al aangaf, als je niet je eigen tabeltype wilt maken, kun je een vooraf gedefinieerde verzameling gebruiken, die hier wordt gedemonstreerd; de hoofdfunctie is hetzelfde, afgezien van de declaratie van de parameter:
create or replace function f42 (in_array sys.odcinumberlist)
return sys_refcursor as
...
De wrapper-functie vult de array iets anders in, maar aan de Java-kant hoeft u alleen deze regel te wijzigen:
ArrayDescriptor aDesc =
ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
Dit betekent ook (zoals ThinkJet ook al aangaf!) dat u uw originele stand-alone query kunt uitvoeren zonder een functie te definiëren:
select a.column_value as id,
case when t.id is null then 'missing'
else 'present' end as status
from table(sys.odcinumberlist(1, 2, 3, 4, 8, 23)) a
left join t42 t on t.id = a.column_value
order by id;
(SQL Fiddle).
En dat betekent dat u de vraag rechtstreeks vanuit Java kunt oproepen:
int[] ids = { 1, 2, 3, 4, 8, 23 };
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
oracle.sql.ARRAY ora_ids = new oracle.sql.ARRAY(aDesc, conn, ids);
sql = "select a.column_value as id, "
+ "case when t.id is null then 'missing' "
+ "else 'present' end as status "
+ "from table(?) a "
+ "left join t42 t on t.id = a.column_value "
+ "order by id";
pStmt = (OraclePreparedStatement) conn.prepareStatement(sql);
pStmt.setArray(1, ora_ids);
rSet = (OracleResultSet) pStmt.executeQuery();
while (rSet.next())
{
System.out.println("id " + rSet.getInt(1) + ": " + rSet.getString(2));
}
... waar je misschien de voorkeur aan geeft.
Er is een vooraf gedefinieerde ODCIVARCHAR2LIST
typ ook, als je tekenreeksen doorgeeft - je originele code lijkt te werken met tekenreeksen, ook al bevatten ze cijfers, dus weet niet zeker welke je echt nodig hebt.
Omdat deze typen zijn gedefinieerd als VARRAY(32767)
je bent beperkt tot 32k-waarden, terwijl het definiëren van je eigen tabel die beperking opheft; maar dat is natuurlijk alleen van belang als je veel waarden doorgeeft.