sql >> Database >  >> RDS >> Oracle

Retourneren van resultaat, zelfs voor elementen in de IN-lijst die niet in de tabel voorkomen

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.



  1. Zelfvoorziening van gebruikersaccounts in PostgreSQL via onbevoegde anonieme toegang

  2. Hoe de PostgreSQL-foutlogboeken te decoderen

  3. Geen gegevens meer om uit socket te lezen

  4. Hoe genereer je een reeks getallen tussen twee getallen?