No puede proporcionar una lista de cadenas de valores de vinculación como using
parámetro, por lo que la única forma que veo para hacer esto es con llamadas SQL dinámicas anidadas, lo cual es un poco complicado y significa tener que declarar (y vincular) todos los parámetros posibles en el interior. declaración dinámica anidada.
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;
/
He usado el mecanismo de cotización alternativo
aquí para reducir la confusión de las comillas simples escapadas. Hay dos niveles anidados de comillas:el exterior delimitado por q'[...]'
y el interior delimitado por q'^...^'
, pero puede usar otros caracteres si esos son un problema debido al contenido real de su tabla. Escapar de esas comillas para dos niveles sería bastante feo y difícil de seguir/acertar; y también tendría que preocuparse por las comillas de escape adicionales en su condition
cadenas, lo que ya sería un problema con su código existente para la segunda muestra que proporcionó, ya que contiene un texto literal dentro.
Con sus dos filas de tabla de muestra y los valores ficticios de fecha/día que mostré arriba, el resultado de la ejecución es:
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
Lo primero que debe tener en cuenta en la declaración generada es la sección de declaración, que tiene que enumerar todos los nombres de variables posibles que pueda tener en input_params
y configúrelos a partir de nuevas variables de vinculación. Debe conocerlos ya en el bloque/procedimiento principal, ya sea como variables locales o como argumentos de procedimiento más probables; pero todos tienen que ser duplicados aquí, ya que en este punto no sabes cuales serán necesarios.
Luego, esa declaración tiene su propio SQL dinámico interno, que es esencialmente lo que estaba haciendo originalmente, pero se concatena en input_params
cadena así como condition
.
La parte importante aquí es la cita. En el primero, por ejemplo, tanto :p_end_date
y :p_start_date
están dentro del segundo nivel de comillas, dentro del q'^...^'
, por lo que están vinculados al SQL dinámico interno, con valores del v_end_date
local y v_start_date
desde ese interior execute immediate
.
Todo el bloque generado se ejecuta con valores de vinculación para todos los nombres de variables posibles, que proporcionan valores para las variables locales (a través de v_start_date date := :v_start_date;
etc.) conservando los tipos de datos; más la bandera de salida.
Ese bloque luego ejecuta su execute immediate
interno declaración que usa solo las variables locales relevantes, que ahora tienen valores vinculados; y el indicador de salida que sigue siendo una variable de vinculación desde el exterior execute immediate
, por lo que el bloque exterior todavía puede ver su resultado.
Puede ver que la segunda declaración generada usa una condición diferente y vincula variables y valores a la primera, y la bandera se evalúa en función de la condición y los parámetros relevantes en cada caso.
Por cierto, podría eliminar la referencia duplicada a :o_flag
(lo cual no es un problema pero me parece un poco confuso) usando una expresión de mayúsculas y minúsculas en su lugar:
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;]';