Od strony SQL możesz zdefiniować typ tabeli i użyć go do połączenia z prawdziwymi danymi, na przykład:
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;
/
Wersja demonstracyjna SQL Fiddle z funkcją opakowującą, dzięki której można bezpośrednio odpytywać, co daje:
ID STATUS
---------- --------------------
1 present
2 present
3 present
4 missing
8 missing
23 present
Z Javy możesz zdefiniować ARRAY
w oparciu o typ tabeli, zapełnij z tablicy Java i wywołaj funkcję bezpośrednio; twoją jednoparametrową zmienną wiązania jest ARRAY
, a otrzymasz z powrotem zestaw wyników, który możesz normalnie powtarzać.
Jako zarys strony Java:
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));
}
Co daje:
id 1: present
id 2: present
id 3: present
id 4: missing
id 8: missing
id 23: present
Jak wspomina Maheswaran Ravisankar, pozwala to na przekazanie dowolnej liczby elementów; nie musisz wiedzieć, ile elementów jest w czasie kompilacji (lub radzić sobie z teoretycznym maksimum), nie jesteś ograniczony maksymalną liczbą wyrażeń dozwolonych w IN
lub przez długość pojedynczego oddzielonego ciągu i nie musisz komponować i rozkładać ciągu, aby przekazać wiele wartości.
Jak zauważył ThinkJet, jeśli nie chcesz tworzyć własnego typu tabeli, możesz użyć predefiniowanej kolekcji, pokazanej tutaj; główna funkcja jest taka sama z wyjątkiem deklaracji parametru:
create or replace function f42 (in_array sys.odcinumberlist)
return sys_refcursor as
...
Funkcja wrappera nieco inaczej zapełnia tablicę, ale po stronie Javy wystarczy zmienić ten wiersz:
ArrayDescriptor aDesc =
ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
Użycie tego oznacza również (jak zauważył ThinkJet!), że możesz uruchomić swoje oryginalne, samodzielne zapytanie bez definiowania funkcji:
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;
(Skrzypce SQL).
A to oznacza, że możesz wywołać zapytanie bezpośrednio z Javy:
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));
}
... co wolisz.
Istnieje predefiniowana ODCIVARCHAR2LIST
wpisz też, jeśli faktycznie przekazujesz ciągi znaków - Twój oryginalny kod wydaje się działać z ciągami, nawet jeśli zawierają liczby, więc nie jesteś pewien, którego naprawdę potrzebujesz.
Ponieważ te typy są zdefiniowane jako VARRAY(32767)
jesteś ograniczony do 32k wartości, podczas gdy zdefiniowanie własnej tabeli usuwa to ograniczenie; ale oczywiście ma to znaczenie tylko wtedy, gdy przekazujesz wiele wartości.