Не можете да предоставите списък с низове от стойности на свързване като using
параметър, така че единственият начин, който виждам да направя това, е с вложени динамични SQL извиквания, което е малко объркващо и означава, че трябва да декларирате (и обвържете) всички възможни параметри във вътрешния. вложен динамичен израз.
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;
/
Използвах алтернативния механизъм за цитиране
тук, за да намалим объркването от избягалите единични кавички. Има две вложени нива на цитиране - външното, ограничено от q'[...]'
и вътрешната, ограничена от q'^...^'
, но можете да използвате други знаци, ако те са проблем поради действителното ви съдържание на таблицата. Избягването на тези цитати за две нива би било доста грозно и трудно за следване/правилно; и също така ще трябва да се тревожите за по-нататъшно избягване на кавички във вашето condition
низове, което вече би представлявало проблем със съществуващия ви код за втората проба, която предоставихте, тъй като съдържа текстов литерал в него.
С вашите два примерни реда в таблицата и фиктивните стойности за дата/ден, които показах над резултата от изпълнението, който е:
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
Първото нещо, което трябва да отбележите в генерирания оператор, е секцията за деклариране, която трябва да изброява всички възможни имена на променливи, които може да имате в input_params
и ги задайте от нови променливи за свързване. Трябва да ги знаете вече в основния блок/процедура, или като локални променливи, или по-вероятни аргументи на процедурата; но всички те трябва да бъдат дублирани тук, тъй като на този етап не знаете кое ще е необходимо.
Тогава този израз има свой собствен вътрешен динамичен SQL, който по същество е това, което сте правили първоначално, но се свързва в input_params
низ, както и condition
.
Важна част тук е цитирането. В първия, например, и двете :p_end_date
и :p_start_date
са във второто ниво на кавички, в q'^...^'
, така че те са обвързани за вътрешния динамичен SQL, със стойности от локалния v_end_date
и v_start_date
от този вътрешен execute immediate
.
Целият генериран блок се изпълнява със стойности на свързване за всички възможни имена на променливи, които предоставят стойности за локалните променливи (чрез v_start_date date := :v_start_date;
и т.н.) при запазване на типовете данни; плюс изходния флаг.
След това този блок изпълнява своето вътрешно execute immediate
израз, използващ само съответните локални променливи, които сега имат обвързани стойности; и изходния флаг, който все още е свързваща променлива от външния execute immediate
, така че външният блок все още може да види своя резултат.
Можете да видите, че вторият генериран оператор използва различно условие и обвързва променливи и стойности с първия, а флагът се оценява въз основа на съответното условие и параметри във всеки случай.
Между другото, можете да премахнете дублиращата се препратка към :o_flag
(което не е проблем, но намирам за малко объркващо), като вместо това използвам израз за малки и големи букви:
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;]';