sql >> Database >  >> RDS >> Oracle

SQL-query uitvoeren die is opgeslagen in een tabel

Dit lijkt een zeer eigenaardige vereiste, en een die moeilijk op een robuuste manier zal kunnen worden opgelost. STMT_OR_VALUE is de belichaming van het anti-patroon Eén kolom twee gebruik. Bovendien vereist het oplossen van STMT_OR_VALUE flow control-logica en het gebruik van dynamische SQL. Het kan dus geen pure SQL-oplossing zijn:je moet PL/SQL gebruiken om de dynamische query samen te stellen en uit te voeren.

Hier is een proof of concept voor een oplossing. Ik heb gekozen voor een functie die je vanuit SQL kunt aanroepen. Het hangt af van één veronderstelling:elke queryreeks die u invoegt in TEST1.STMT_OR_VALUE heeft een projectie van een enkele numerieke kolom en elke waardereeks is een CSV met alleen numerieke gegevens . Met deze voorwaarde is het eenvoudig om een ​​functie te construeren die ofwel een dynamische query uitvoert of de string tokeniseert in een reeks getallen; beide worden in bulk verzameld in een geneste tabel:

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

Merk op dat er meer dan één manier is om een ​​dynamische SQL-instructie uit te voeren en een veelvoud aan manieren om een ​​CSV te tokeniseren in een reeks getallen. Mijn beslissingen zijn willekeurig:voel je vrij om je favoriete methoden hier te vervangen.

Deze functie kan worden aangeroepen met een table() bel:

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
/

Het grote voordeel van deze aanpak is dat het de logica rond de evaluatie van STMT_OR_VALUE inkapselt en het gebruik van dynamische SQL verbergt. Daarom is het gemakkelijk om het in elke SQL-instructie te gebruiken terwijl de leesbaarheid behouden blijft, of om verdere mechanismen toe te voegen voor het genereren van een set ID's.

Deze oplossing is echter broos. Het werkt alleen als de waarden in de test1 tafel zich aan de regels houden. Dat wil zeggen, ze moeten niet alleen converteerbaar zijn naar een stroom van enkele getallen, maar de SQL-instructies moeten ook geldig en uitvoerbaar zijn door EXECUTE IMMEDIATE. De achterste puntkomma in de voorbeeldgegevens van de vraag is bijvoorbeeld ongeldig en zou EXECUTE IMMEDIATE doen slingeren. Dynamische SQL is moeilijk, niet in de laatste plaats omdat het compilatiefouten omzet in runtime-fouten.



  1. Vernieuw de inhoud van een div alleen als er nieuwe inhoud aan de database is toegevoegd

  2. Moet u de gegevenstypen MONEY of DECIMAL(x,y) in SQL Server kiezen?

  3. select statement in postgres functie aangeroepen in een trigger

  4. Is het mogelijk om een ​​dynamische externe sleutel te hebben, en wat is het beste/juiste om dit te doen?