Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Rückgabe des Ergebnisses auch für Elemente in der IN-Liste, die nicht in der Tabelle vorhanden sind

Von der SQL-Seite aus könnten Sie einen Tabellentyp definieren und diesen verwenden, um ihn mit Ihren echten Daten zu verknüpfen, etwa so:

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 mit einer Wrapper-Funktion, damit Sie sie direkt abfragen können, was Folgendes ergibt:

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

Von Java aus können Sie ein ARRAY definieren basierend auf dem Tabellentyp aus einem Java-Array füllen und die Funktion direkt aufrufen; Ihre Einzelparameter-Bind-Variable ist das ARRAY , und Sie erhalten eine Ergebnismenge zurück, über die Sie wie gewohnt iterieren können.

Als Umriss der Java-Seite:

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

Was ergibt:

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

Wie Maheswaran Ravisankar erwähnt, erlaubt dies, eine beliebige Anzahl von Elementen zu übergeben; Sie müssen nicht wissen, wie viele Elemente zur Kompilierzeit vorhanden sind (oder mit einem theoretischen Maximum umgehen), Sie sind nicht durch die maximale Anzahl von Ausdrücken begrenzt, die in einem IN zulässig sind oder durch die Länge einer einzelnen Zeichenfolge mit Trennzeichen, und Sie müssen eine Zeichenfolge nicht zusammensetzen und zerlegen, um mehrere Werte zu übergeben.

Wie ThinkJet betonte, können Sie, wenn Sie keinen eigenen Tabellentyp erstellen möchten, eine vordefinierte Sammlung verwenden, die hier demonstriert wird. die Hauptfunktion ist die gleiche abgesehen von der Deklaration des Parameters:

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

Die Wrapper-Funktion füllt das Array etwas anders, aber auf der Java-Seite müssen Sie nur diese Zeile ändern:

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

Wenn Sie dies verwenden, bedeutet dies auch (wie ThinkJet auch darauf hingewiesen hat!), dass Sie Ihre ursprüngliche eigenständige Abfrage ausführen können, ohne eine Funktion zu definieren:

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

Und das bedeutet, dass Sie die Abfrage direkt aus Java heraus aufrufen können:

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

... was Ihnen vielleicht lieber ist.

Es gibt eine vordefinierte ODCIVARCHAR2LIST Geben Sie auch ein, wenn Sie tatsächlich Zeichenfolgen übergeben - Ihr ursprünglicher Code scheint mit Zeichenfolgen zu arbeiten, obwohl sie Zahlen enthalten, also sind Sie sich nicht sicher, welche Sie wirklich brauchen.

Weil diese Typen als VARRAY(32767) definiert sind Sie sind auf 32.000 Werte beschränkt, während die Definition Ihrer eigenen Tabelle diese Einschränkung aufhebt; aber das spielt natürlich nur eine Rolle, wenn Sie viele Werte übergeben.