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

Ausführen einer in einer Tabelle gespeicherten SQL-Abfrage

Dies scheint eine sehr eigentümliche Anforderung zu sein, die auf robuste Weise schwer zu lösen sein wird. STMT_OR_VALUE ist die Verkörperung des One Column Two Usages Anti-Musters. Darüber hinaus erfordert das Auflösen von STMT_OR_VALUE eine Flusssteuerungslogik und die Verwendung von dynamischem SQL. Folglich kann es keine reine SQL-Lösung sein:Sie müssen PL/SQL verwenden, um die dynamische Abfrage zusammenzustellen und auszuführen.

Hier ist ein Proof of Concept für eine Lösung. Ich habe mich für eine Funktion entschieden, die man aus SQL heraus aufrufen kann. Es hängt von einer Annahme ab:Jede Abfragezeichenfolge, die Sie in TEST1.STMT_OR_VALUE einfügen, hat eine Projektion einer einzelnen numerischen Spalte und jede Wertezeichenfolge ist nur eine CSV-Datei mit numerischen Daten . Unter dieser Bedingung ist es einfach, eine Funktion zu konstruieren, die entweder eine dynamische Abfrage ausführt oder die Zeichenkette in eine Reihe von Zahlen zerlegt; beide werden massenhaft in einer verschachtelten Tabelle gesammelt:

create or replace function get_ids (p_name in test1.name%type) 
  return sys.odcinumberlist
is
  l_rec test1%rowtype;
  return_value sys.odcinumberlist;
begin

  select * into l_rec
  from test1
  where name = p_name;

  if l_rec.type = 'SQL_QUERY' then 
    -- execute a query
    execute immediate l_rec.stmt_or_value
      bulk collect into return_value;
  else
    -- tokenize a string
    select xmltab.tkn
    bulk collect into return_value
    from ( select l_rec.stmt_or_value from dual) t
        , xmltable(  'for $text in ora:tokenize($in, ",") return $text'
                      passing stmt_or_value as "in"
                      columns tkn number path '.'
                   ) xmltab;
  end if;
  return return_value;
end;
/

Beachten Sie, dass es mehr als eine Möglichkeit gibt, eine dynamische SQL-Anweisung auszuführen, und eine Vielzahl von Möglichkeiten, eine CSV-Datei in eine Reihe von Zahlen zu tokenisieren. Meine Entscheidungen sind willkürlich:Fühlen Sie sich frei, Ihre bevorzugten Methoden hier zu ersetzen.

Diese Funktion kann mit einem table() aufgerufen werden Aufruf:

select * 
from data
where id in ( select * from table(get_ids('first'))) -- execute query
or    id in ( select * from table(get_ids('second'))) -- get string of values
/

Der große Vorteil dieses Ansatzes besteht darin, dass er die Logik rund um die Auswertung von STMT_OR_VALUE kapselt und die Verwendung von Dynamic SQL verbirgt. Folglich ist es einfach, es in jeder SQL-Anweisung unter Beibehaltung der Lesbarkeit zu verwenden oder weitere Mechanismen zum Generieren eines Satzes von IDs hinzuzufügen.

Diese Lösung ist jedoch spröde. Es funktioniert nur, wenn die Werte in test1 Tisch befolgen die Regeln. Das heißt, sie müssen nicht nur in einen Strom aus einzelnen Zahlen konvertierbar sein, sondern die SQL-Anweisungen müssen auch gültig und durch EXECUTE IMMEDIATE ausführbar sein. Beispielsweise ist das nachgestellte Semikolon in den Beispieldaten der Frage ungültig und würde EXECUTE SOFORT auslösen. Dynamisches SQL ist nicht zuletzt deshalb schwierig, weil es Kompilierungsfehler in Laufzeitfehler umwandelt.