Nemůžete zadat seznam řetězců hodnot vazby jako using
parametr, takže jediný způsob, jak to udělat, je pomocí vnořených dynamických volání SQL, což je trochu chaotické a znamená to, že je nutné deklarovat (a svázat) všechny možné parametry ve vnitřním. vnořený dynamický příkaz.
declare
v_execute_statement varchar2(4000);
v_flag varchar2(1);
v_start_date date := date '2018-01-01';
v_end_date date := date '2018-01-31';
v_joining_day varchar2(9) := 'MONDAY';
begin
-- loop over all rows for demo
for rec in (
select condition, input_params
From your_table
)
loop
v_execute_statement := q'[
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF ]' || rec.condition || q'[ THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING ]' || rec.input_params || q'[, OUT :v_flag;
END;]';
dbms_output.put_line('Statement: ' || v_execute_statement);
EXECUTE IMMEDIATE v_execute_statement
USING v_start_date, v_end_date, v_joining_day, OUT v_flag;
dbms_output.put_line('Result flag: ' || v_flag);
end loop;
end;
/
Použil jsem alternativní mechanismus nabídek
zde, aby se omezil zmatek z uniklých jednoduchých uvozovek. Existují dvě vnořené úrovně uvozovek – vnější oddělená q'[...]'
a vnitřní oddělený q'^...^'
, ale můžete použít i jiné znaky, pokud jsou kvůli obsahu vaší tabulky problém. Uniknout z těchto uvozovek pro dvě úrovně by bylo docela ošklivé a bylo by těžké to dodržet/napravit; a také byste se museli starat o další únikové uvozovky ve vašem condition
řetězců, což by již představovalo problém s vaším stávajícím kódem pro druhý příklad, který jste poskytli, protože obsahuje textový doslovný text.
S vašimi dvěma ukázkovými řádky tabulky a fiktivními hodnotami data/den, které jsem ukázal nad výstupem ze spuštění, je:
Statement:
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF :p_end_date < :p_start_date THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING v_end_date, IN v_start_date, OUT :o_flag;
END;
Result flag: N
Statement:
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
IF :p_joining_day = 'MONDAY' THEN
:o_flag := 'Y';
ELSE
:o_flag := 'N';
END IF;
END;^'
USING v_joining_day, OUT :o_flag;
END;
Result flag: Y
První věc, kterou je třeba si ve vygenerovaném příkazu povšimnout, je sekce deklarace, která musí vypsat všechny možné názvy proměnných, které můžete mít v input_params
a nastavte je z nových proměnných vazby. Musíte je znát již v hlavním bloku/proceduře, buď jako lokální proměnné nebo pravděpodobnější argumenty procedury; ale všechny jsou zde duplikovány, protože v tuto chvíli nevíte, která bude potřeba.
Pak má tento příkaz svůj vlastní vnitřní dynamický SQL, což je v podstatě to, co jste původně dělali, ale zřetězí se v input_params
řetězec a také condition
.
Důležitou součástí je zde citace. V prvním z nich například oba :p_end_date
a :p_start_date
jsou uvnitř druhé úrovně uvozovek, v rámci q'^...^'
, takže jsou vázány na vnitřní dynamický SQL s hodnotami z místního v_end_date
a v_start_date
z toho vnitřního execute immediate
.
Celý vygenerovaný blok se provede s hodnotami vazby pro všechny možné názvy proměnných, které poskytují hodnoty pro lokální proměnné (přes v_start_date date := :v_start_date;
atd.) při zachování datových typů; plus výstupní příznak.
Tento blok pak provede svůj interní execute immediate
příkaz pouze s použitím relevantních lokálních proměnných, které nyní mají vázané hodnoty; a výstupní příznak, který je stále proměnnou vazby z vnějšího execute immediate
, takže vnější blok stále vidí svůj výsledek.
Můžete vidět, že druhý vygenerovaný příkaz používá jinou podmínku a váže proměnné a hodnoty k prvnímu, a příznak je v každém případě vyhodnocen na základě relevantní podmínky a parametrů.
Mimochodem, můžete odstranit duplicitní odkaz na :o_flag
(což není problém, ale považuji to za trochu matoucí) použitím výrazu typu case:
v_execute_statement := q'[
DECLARE
v_start_date date := :v_start_date;
v_end_date date := :v_end_date;
v_joining_day varchar2(9) := :v_joining_day;
BEGIN
EXECUTE IMMEDIATE q'^
BEGIN
:o_flag := CASE WHEN ]' || rec.condition || q'[ THEN 'Y' ELSE 'N' END;
END;^'
USING OUT :v_flag, ]' || rec.input_params || q'[;
END;]';