sql >> Base de Datos >  >> RDS >> Oracle

Devolver resultado incluso para elementos en la lista IN que no existen en la tabla

Desde el lado de SQL, puede definir un tipo de tabla y usarlo para unir sus datos reales, algo como:

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;
/

Demostración de SQL Fiddle con una función contenedora para que pueda consultarla directamente, lo que da:

        ID STATUS             
---------- --------------------
         1 present              
         2 present              
         3 present              
         4 missing              
         8 missing              
        23 present              

Desde Java puedes definir un ARRAY según el tipo de tabla, rellene desde una matriz de Java y llame a la función directamente; su variable de enlace de parámetro único es el ARRAY , y obtendrá un conjunto de resultados sobre el que puede iterar normalmente.

Como esquema del lado de 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));
}

Lo que da:

id 1: present
id 2: present
id 3: present
id 4: missing
id 8: missing
id 23: present

Como menciona Maheswaran Ravisankar, esto permite pasar cualquier número de elementos; no necesita saber cuántos elementos hay en tiempo de compilación (o tratar con un máximo teórico), no está limitado por la cantidad máxima de expresiones permitidas en un IN o por la longitud de una sola cadena delimitada, y no tiene que componer y descomponer una cadena para pasar múltiples valores.

Como señaló ThinkJet, si no desea crear su propio tipo de tabla, puede usar una colección predefinida, que se muestra aquí; la función principal es la misma aparte de la declaración del parámetro:

create or replace function f42 (in_array sys.odcinumberlist)
return sys_refcursor as
...    

La función contenedora llena la matriz de forma ligeramente diferente, pero en el lado de Java solo necesita cambiar esta línea:

ArrayDescriptor aDesc =
  ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );

Usar esto también significa (¡como también señaló ThinkJet!) que puede ejecutar su consulta independiente original sin definir una función:

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;

(Violín SQL).

Y eso significa que puede llamar a la consulta directamente desde Java:

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));
}

... que prefieras.

Hay una ODCIVARCHAR2LIST predefinida escriba también, si en realidad está pasando cadenas:su código original parece estar funcionando con cadenas a pesar de que contienen números, por lo que no está seguro de cuál necesita realmente.

Porque estos tipos se definen como VARRAY(32767) está limitado a 32k valores, mientras que definir su propia tabla elimina esa restricción; pero obviamente eso solo importa si estás pasando muchos valores.