Dette virker som et meget ejendommeligt krav, og et som vil være svært at løse på en robust måde. STMT_OR_VALUE er udførelsesformen af One Column Two Usages anti-mønsteret. Desuden kræver løsning af STMT_OR_VALUE flowkontrollogik og brug af dynamisk SQL. Det kan derfor ikke være en ren SQL-løsning:du skal bruge PL/SQL til at samle og udføre den dynamiske forespørgsel.
Her er et proof of concept for en løsning. Jeg har valgt en funktion, som du kan kalde fra SQL. Det afhænger af én antagelse:hver forespørgselsstreng, du indsætter i TEST1.STMT_OR_VALUE har en projektion af en enkelt numerisk kolonne og hver værdistreng er en CSV med kun numeriske data . Med dette forbehold er det enkelt at konstruere en funktion, som enten udfører en dynamisk forespørgsel eller tokeniserer strengen til en række tal; som begge er samlet i en indlejret 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;
/
Bemærk, at der er mere end én måde at udføre en dynamisk SQL-sætning på og en mangfoldighed af måder at tokenisere en CSV til en række tal. Mine beslutninger er vilkårlige:Du er velkommen til at erstatte dine foretrukne metoder her.
Denne funktion kan aktiveres med en table()
ring:
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
/
Den store fordel ved denne tilgang er, at den indkapsler logikken omkring evalueringen af STMT_OR_VALUE og skjuler brugen af Dynamic SQL. Det er derfor nemt at anvende det i enhver SQL-sætning, mens læsbarheden bevares, eller at tilføje yderligere mekanismer til generering af et sæt id'er.
Denne løsning er dog skør. Det vil kun fungere, hvis værdierne i test1
bord overholde reglerne. Det vil sige, at de ikke kun skal kunne konverteres til en strøm af enkelte tal, men SQL-sætningerne skal være gyldige og eksekverbare af EXECUTE IMMEDIATE. For eksempel er det efterfølgende semikolon i spørgsmålets eksempeldata ugyldigt og vil få EXECUTE IMMEDIATE til at kaste. Dynamisk SQL er svært, ikke mindst fordi det konverterer kompileringsfejl til runtime-fejl.