Oracle
 sql >> Database >  >> RDS >> Oracle

eseguire query SQL memorizzate in una tabella

Questo sembra un requisito molto particolare e che sarà difficile da risolvere in modo robusto. STMT_OR_VALUE è l'incarnazione dell'anti-modello One Column Two Usages. Inoltre, la risoluzione di STMT_OR_VALUE richiede una logica di controllo del flusso e l'uso di SQL dinamico. Di conseguenza non può essere una pura soluzione SQL:è necessario utilizzare PL/SQL per assemblare ed eseguire la query dinamica.

Ecco un proof of concept per una soluzione. Ho optato per una funzione che puoi chiamare da SQL. Dipende da un presupposto:ogni stringa di query che inserisci in TEST1.STMT_OR_VALUE ha una proiezione di una singola colonna numerica e ogni stringa di valore è un CSV di soli dati numerici . Con questa condizione è semplice costruire una funzione che esegua una query dinamica o tokenizzi la stringa in una serie di numeri; entrambi vengono raccolti in blocco in una tabella nidificata:

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

Si noti che esiste più di un modo per eseguire un'istruzione SQL dinamica e una molteplicità di modi per tokenizzare un CSV in una serie di numeri. Le mie decisioni sono arbitrarie:sentiti libero di sostituire i tuoi metodi preferiti qui.

Questa funzione può essere invocata con una table() chiama:

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
/

Il grande vantaggio di questo approccio è che incapsula la logica attorno alla valutazione di STMT_OR_VALUE e nasconde l'uso di Dynamic SQL. Di conseguenza è facile utilizzarlo in qualsiasi istruzione SQL pur mantenendo la leggibilità o aggiungere ulteriori meccanismi per generare un insieme di ID.

Tuttavia, questa soluzione è fragile. Funzionerà solo se i valori nel test1 tavolo obbedire alle regole. Cioè, non solo devono essere convertibili in un flusso di numeri singoli, ma le istruzioni SQL devono essere valide ed eseguibili da EXECUTE IMMEDIATE. Ad esempio, il punto e virgola finale nei dati di esempio della domanda non è valido e causerebbe l'esecuzione di ESEGUI IMMEDIATO. L'SQL dinamico è difficile non da ultimo perché converte gli errori di compilazione in errori di runtime.