Oracle
 sql >> Base de données >  >> RDS >> Oracle

exécuter une requête SQL stockée dans une table

Cela semble une exigence très particulière, et qui sera difficile à résoudre de manière robuste. STMT_OR_VALUE est l'incarnation de l'anti-pattern One Column Two Usages. De plus, la résolution de STMT_OR_VALUE nécessite une logique de contrôle de flux et l'utilisation de SQL dynamique. Par conséquent, il ne peut pas s'agir d'une solution purement SQL :vous devez utiliser PL/SQL pour assembler et exécuter la requête dynamique.

Voici une preuve de concept pour une solution. J'ai opté pour une fonction que vous pouvez appeler depuis SQL. Cela dépend d'une hypothèse :chaque chaîne de requête que vous insérez dans TEST1.STMT_OR_VALUE a une projection d'une seule colonne numérique et chaque chaîne de valeur est un CSV de données numériques uniquement . Avec cette condition, il est simple de construire une fonction qui exécute une requête dynamique ou segmente la chaîne en une série de nombres ; qui sont tous deux collectés en masse dans une table imbriquée :

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;
/

Notez qu'il existe plusieurs façons d'exécuter une instruction SQL dynamique et une multiplicité de façons de segmenter un CSV en une série de nombres. Mes décisions sont arbitraires :n'hésitez pas à substituer vos méthodes préférées ici.

Cette fonction peut être invoquée avec un table() appeler :

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
/

Le grand avantage de cette approche est qu'elle encapsule la logique autour de l'évaluation de STMT_OR_VALUE et masque l'utilisation de Dynamic SQL. Par conséquent, il est facile de l'utiliser dans n'importe quelle instruction SQL tout en conservant la lisibilité, ou d'ajouter d'autres mécanismes pour générer un ensemble d'ID.

Cependant, cette solution est fragile. Cela ne fonctionnera que si les valeurs dans le test1 table obéir aux règles. Autrement dit, non seulement ils doivent être convertibles en un flux de nombres uniques, mais les instructions SQL doivent être valides et exécutables par EXECUTE IMMEDIATE. Par exemple, le point-virgule final dans les exemples de données de la question n'est pas valide et entraînerait le lancement de EXECUTE IMMEDIATE. Le SQL dynamique est difficile, notamment parce qu'il convertit les erreurs de compilation en erreurs d'exécution.