Oracle
 sql >> Database >  >> RDS >> Oracle

Restituisce il risultato anche per gli elementi nell'elenco IN che non esistono nella tabella

Dal lato SQL puoi definire un tipo di tabella e usarlo per unirti ai tuoi dati reali, qualcosa come:

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

Demo di SQL Fiddle con una funzione wrapper in modo da poterla interrogare direttamente, che fornisce:

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

Da Java puoi definire un ARRAY in base al tipo di tabella, compilare da un array Java e chiamare direttamente la funzione; la tua variabile di associazione a parametro singolo è ARRAY e ottieni un set di risultati su cui puoi scorrere normalmente.

Come schema del lato 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));
}

Che dà:

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

Come menziona Maheswaran Ravisankar, ciò consente di passare un numero qualsiasi di elementi; non è necessario sapere quanti elementi ci sono in fase di compilazione (o affrontare un massimo teorico), non si è limitati dal numero massimo di espressioni consentite in un IN o dalla lunghezza di una singola stringa delimitata e non è necessario comporre e scomporre una stringa per passare più valori.

Come ha sottolineato ThinkJet, se non si desidera creare il proprio tipo di tabella è possibile utilizzare una raccolta predefinita, illustrata qui; la funzione principale è la stessa a parte la dichiarazione del parametro:

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

La funzione wrapper popola l'array in modo leggermente diverso, ma sul lato Java devi solo cambiare questa riga:

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

Usare questo significa anche (come ha sottolineato anche ThinkJet!) che puoi eseguire la tua query autonoma originale senza definire una funzione:

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).

Ciò significa che puoi chiamare la query direttamente da 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));
}

... che potresti preferire.

C'è un ODCIVARCHAR2LIST predefinito digita anche tu, se stai effettivamente passando delle stringhe:il tuo codice originale sembra funzionare con le stringhe anche se contengono numeri, quindi non sono sicuro di quale ti serva davvero.

Perché questi tipi sono definiti come VARRAY(32767) sei limitato a 32k valori, mentre la definizione della tua tabella rimuove quella restrizione; ma ovviamente questo conta solo se stai trasmettendo molti valori.