¿Cómo puedo utilizar una instrucción SQL almacenada en una tabla como parte de otro estado de cuenta?

StackOverflow https://stackoverflow.com/questions/3466320

Pregunta

En nuestra base de datos de Oracle que tiene una tabla llamada NORMAS, con un campo llamado SQLQuery. Este campo es un varchar con una instrucción SQL almacenada. El PK es DM_PROJECT.

Una declaración típica que se almacena podría ser

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > 500000

Quiero hacer algo como esto:

select 
  * 
from 
  customers 
where
     accountnumber like 'A%'
  or salesregion = 999
  or accountnumber in
     (
       <run the query SQLQUERY from RULES where DM_PROJECT=:DM_PROJECT>
     )

Puede hacerse esto?

(Problema secundario: ¿Se puede hacer si la consulta almacenado utiliza sus propias variables, como

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATEDSALES > :LIMIT 

)

¿Fue útil?

Solución

Una pregunta interesante por cierto. Hay dos aspectos en este.

La primera es si se trata de una idea buena. El problema es que el texto de la regla es invisible a la base de datos. No se mostrará en comprobaciones de dependencia, por lo que el análisis de impacto se endurece. Obviamente (o tal vez no, obviamente) la sintaxis de la regla sólo puede ser verificada mediante la ejecución de la misma. Esto puede crear problemas con la adición de reglas. Por lo que también puede ser un problema de mantenimiento. Y, como veremos más adelante, una vez que se mueve más allá de las consultas simplistas que es difícil de programa con.

El segundo aspecto es si es posible. Es. Tenemos que utilizar SQL dinámico; la combinación de SQL dinámico con SQL estático es factible, pero gnarly.

create table rules (project_name varchar2(30)
                    , rule_name varchar2(30)
                    , rule_text varchar2(4000) )
/
insert into rules 
values ('SO', 'ACC_SALES'
        , 'select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > 500000 ')
/
create table customers (accountnumber number(7,0) 
                        , name varchar2(20)
                        , accumulated_sales number
                        , sales_region varchar2(3))
/
insert into customers values (111, 'ACME Industries', 450000, 'AA')
/
insert into customers values (222, 'Tyrell Corporation', 550000, 'BB')
/
insert into customers values (333, 'Lorax Textiles Co', 500000, 'BB')
/

Esta función obtiene una regla, lo ejecuta y devuelve una matriz numérica.

create or replace type rule_numbers as table of number
/

create or replace function exec_numeric_rule
    ( p_pname in rules.project_name%type
      ,  p_rname in rules.rule_name%type )
    return rule_numbers
is
    return_value rule_numbers;
    stmt rules.rule_text%type;
begin
    select rule_text into stmt
    from rules
    where project_name = p_pname
    and   rule_name = p_rname;

    execute immediate stmt 
        bulk collect into return_value;

    return return_value;
end exec_numeric_rule;
/

La prueba de lo permites.

SQL> select * from customers
  2  where accountnumber in
  3      ( select * from table (exec_numeric_rule('SO', 'ACC_SALES')))
  4  /

ACCOUNTNUMBER NAME                 ACCUMULATED_SALES SAL
------------- -------------------- ----------------- ---
          222 Tyrell Corporation              550000 BB

1 row selected.

SQL>

¿Cuál es la única respuesta correcta.

Pero ahora llegamos a su pregunta suplementaria:

  

"¿Se puede hacer si la consulta almacenada   utiliza sus propias variables "

Sí, se puede, pero las cosas empiezan a ser un poco más frágil. Nueva regla:

insert into rules 
values ('SO', 'ACC_SALES_VAR'
        , 'select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > :LMT ')
/

modificar la función de aplicarlo:

create or replace function exec_numeric_rule
    ( p_pname in rules.project_name%type
      , p_rname in rules.rule_name%type
      , p_variable in number := null)
    return rule_numbers
is
    return_value rule_numbers;
    stmt rules.rule_text%type;
begin
    select rule_text into stmt
    from rules
    where project_name = p_pname
    and   rule_name = p_rname;

    if p_variable is null then
        execute immediate stmt 
            bulk collect into return_value;
    else
        execute immediate stmt 
            bulk collect into return_value
            using p_variable;        
    end if;

    return return_value;
end exec_numeric_rule;
/

Dedos cruzados!

SQL> select * from customers
  2  where accountnumber in
  3      ( select * from table (exec_numeric_rule('SO', 'ACC_SALES_VAR', 480000)))
  4  /

ACCOUNTNUMBER NAME                 ACCUMULATED_SALES SAL
------------- -------------------- ----------------- ---
          222 Tyrell Corporation              550000 BB
          333 Lorax Textiles Co               500000 BB

2 rows selected.

SQL>

Bueno, por lo que todavía funciona. Sin embargo, se puede ver que las permutaciones no es agradable. Si desea pasar más de un argumento a la regla, entonces necesita más funciones o una lógica interna reviradas. Si desea conjuntos de retorno de fechas o cadenas que necesita más funciones. Si desea pasar parámetros P_VARIABLE de diferentes data_types es posible que tenga más funciones. Que sin duda necesita algún tipo de cheques pre-condiciones.

Lo que viene de nuevo a mi primer punto:? Sí se puede hacer, pero vale la pena la molestia

Otros consejos

Puede utilizar SQL dinámico (Ejecutar inmediata) ..Por favor referirse Ejecutar inmediata para más detalles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top