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.