sql >> Databasteknik >  >> RDS >> Oracle

Returnerar resultat även för element i IN-listan som inte finns i tabellen

Från SQL-sidan kan du definiera en tabelltyp och använda den för att ansluta till dina riktiga data, något som:

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 med en wrapper-funktion så att du kan fråga den direkt, vilket ger:

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

Från Java kan du definiera en ARRAY baserat på tabelltypen, fyll i från en Java-array och anrop funktionen direkt; din enda parameter bindningsvariabel är ARRAY , och du får tillbaka en resultatuppsättning som du kan upprepa som vanligt.

Som en översikt över Java-sidan:

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

Vilket ger:

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

Som Maheswaran Ravisankar nämner tillåter detta valfritt antal element att passeras; du behöver inte veta hur många element som finns vid kompilering (eller hantera ett teoretiskt maximum), du är inte begränsad av det maximala antalet uttryck som tillåts i en IN eller med längden på en enskild avgränsad sträng, och du behöver inte komponera och dekomponera en sträng för att skicka flera värden.

Som ThinkJet påpekade, om du inte vill skapa din egen tabelltyp kan du använda en fördefinierad samling, som visas här; huvudfunktionen är densamma förutom deklarationen av parametern:

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

Omslagsfunktionen fyller arrayen något annorlunda, men på Java-sidan behöver du bara ändra denna rad:

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

Att använda detta innebär också (som ThinkJet också påpekade!) att du kan köra din ursprungliga fristående fråga utan att definiera en funktion:

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

Och det betyder att du kan ringa frågan direkt från 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));
}

... vilket du kanske föredrar.

Det finns en fördefinierad ODCIVARCHAR2LIST skriv också, om du faktiskt skickar strängar - din ursprungliga kod verkar fungera med strängar även om de innehåller siffror, så du är inte säker på vilken du verkligen behöver.

Eftersom dessa typer är definierade som VARRAY(32767) du är begränsad till 32k värden, medan du definierar din egen tabell tar bort den begränsningen; men uppenbarligen spelar det bara roll om du förmedlar många värderingar.



  1. Vad är SQL Server dödläge?

  2. Databaskorruption

  3. Hur man installerar Neo4j på Ubuntu 20.04

  4. När du använder GETDATE() på många ställen, är det bättre att använda en variabel?