Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Retornando resultado mesmo para elementos na lista IN que não existem na tabela


Do lado do SQL, você pode definir um tipo de tabela e usá-lo para unir seus dados reais, 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;
/

Demonstração do SQL Fiddle com uma função wrapper para que você possa consultá-la diretamente, o que fornece:
        ID STATUS             
---------- --------------------
         1 present              
         2 present              
         3 present              
         4 missing              
         8 missing              
        23 present              

De Java você pode definir um ARRAY com base no tipo de tabela, preencha a partir de uma matriz Java e chame a função diretamente; sua variável de ligação de parâmetro único é o ARRAY , e você recebe de volta um conjunto de resultados que pode iterar normalmente.

Como um esboço do lado 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));
}

Que dá:
id 1: present
id 2: present
id 3: present
id 4: missing
id 8: missing
id 23: present

Como Maheswaran Ravisankar menciona, isso permite que qualquer número de elementos seja passado; você não precisa saber quantos elementos existem em tempo de compilação (ou lidar com um máximo teórico), você não está limitado pelo número máximo de expressões permitidas em um IN ou pelo comprimento de uma única string delimitada, e você não precisa compor e decompor uma string para passar vários valores.

Como o ThinkJet apontou, se você não quiser criar seu próprio tipo de tabela, você pode usar uma coleção predefinida, demonstrada aqui; a função principal é a mesma, exceto a declaração do parâmetro:
create or replace function f42 (in_array sys.odcinumberlist)
return sys_refcursor as
...    

A função wrapper preenche o array de maneira um pouco diferente, mas no lado Java você só precisa alterar esta linha:
ArrayDescriptor aDesc =
  ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );

Usar isso também significa (como a ThinkJet também apontou!) que você pode executar sua consulta autônoma original sem definir uma função:
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 violino).

E isso significa que você pode chamar a consulta diretamente do 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 você pode preferir.

Há um ODCIVARCHAR2LIST predefinido digite também, se você estiver realmente passando strings - seu código original parece estar trabalhando com strings mesmo que elas contenham números, então não tenho certeza de qual você realmente precisa.

Como esses tipos são definidos como VARRAY(32767) você está limitado a 32k valores, enquanto definir sua própria tabela remove essa restrição; mas obviamente isso só importa se você estiver passando muitos valores.