Dynami c Metri c Расчет в Oracle SQL - PullRequest
0 голосов
/ 14 июля 2020

Я пытаюсь автоматизировать расчет некоторых показателей в Oracle. У меня есть около 50 показателей, которые нужно рассчитать на основе некоторой информации низкого уровня. Каждый показатель c имеет разные логики вычислений c, хотя они могут использовать общие точки данных. У меня есть весь текст вычислений, записанный в поле вместе с базовыми точками данных в таблице.

Я пытаюсь написать функцию с использованием Dynami c SQL для выполнения работы. Ниже приведен всего лишь блок кода из подхода, которому я следую. И, конечно же, я делаю это неправильно, поэтому он вызывает ошибки:

DECLARE
    A NUMBER :=10;
    B NUMBER :=20;
    C NUMBER :=40;
    D NUMBER :=35;
    OUTPUT_VAR NUMBER;
    SQL_TEXT VARCHAR2(50);
BEGIN
--    SQL_TEXT:='OUTPUT_VAR:=A+B;';
--    SQL_TEXT:='OUTPUT_VAR:=A+B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=A/D;';
--    SQL_TEXT:='OUTPUT_VAR:=A*B;';
--    SQL_TEXT:='OUTPUT_VAR:=B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=C/D;';
--    SQL_TEXT:='OUTPUT_VAR:=B/C;';
    SQL_TEXT:='OUTPUT_VAR:=A+D;';
    
    EXECUTE IMMEDIATE SQL_TEXT;
    DBMS_OUTPUT.PUT(OUTPUT_VAR);
END;

Вот ошибка, которую я получаю:

Error starting at line : 1 in command -
DECLARE
    A NUMBER :=10;
    B NUMBER :=20;
    C NUMBER :=40;
    D NUMBER :=35;
    OUTPUT_VAR NUMBER;
    SQL_TEXT VARCHAR2(50);
BEGIN
--    SQL_TEXT:='OUTPUT_VAR:=A+B;';
--    SQL_TEXT:='OUTPUT_VAR:=A+B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=A/D;';
--    SQL_TEXT:='OUTPUT_VAR:=A*B;';
--    SQL_TEXT:='OUTPUT_VAR:=B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=C/D;';
--    SQL_TEXT:='OUTPUT_VAR:=B/C;';
    SQL_TEXT:='OUTPUT_VAR:=A+D;';

    EXECUTE IMMEDIATE SQL_TEXT;
    DBMS_OUTPUT.PUT(OUTPUT_VAR);
END;
Error report -
ORA-00900: invalid SQL statement
ORA-06512: at line 18
00900. 00000 -  "invalid SQL statement"
*Cause:    
*Action:

Просьба о помощи заставить эту работу. Ваши отзывы приветствуются, спасибо!

Ответы [ 2 ]

1 голос
/ 14 июля 2020
DECLARE
    A NUMBER :=10;
    B NUMBER :=20;
    C NUMBER :=40;
    D NUMBER :=35;
    OUTPUT_VAR NUMBER;
    SQL_TEXT VARCHAR2(50);
function calc(p_cmd in varchar2) return number as
   res number;
begin
    execute immediate '
       Declare
           A NUMBER :=:a;
           B NUMBER :=:b;
           C NUMBER :=:c;
           D NUMBER :=:d;
           OUTPUT_VAR number;
        Begin 
           '||p_cmd||'  
           :res:= output_var; 
        end;' 
        Using a, b, c, d, out res;
     Return res;
End;
BEGIN
--    SQL_TEXT:='OUTPUT_VAR:=A+B;';
--    SQL_TEXT:='OUTPUT_VAR:=A+B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=A/D;';
--    SQL_TEXT:='OUTPUT_VAR:=A*B;';
--    SQL_TEXT:='OUTPUT_VAR:=B+C;';
--    SQL_TEXT:='OUTPUT_VAR:=C/D;';
--    SQL_TEXT:='OUTPUT_VAR:=B/C;';
    SQL_TEXT:='OUTPUT_VAR:=A+D;';
    
    OUTPUT_VAR:=calc(SQL_TEXT) ;
    DBMS_OUTPUT.PUT_LINE(OUTPUT_VAR);
END; 
0 голосов
/ 16 июля 2020

Другой способ сделать это в SQL без PL / SQL - использовать XMLTABLE или XMLQUERY. XQUERY позволяет очень легко выполнять простые вычисления, например:

select * 
from xmltable(
       '$A + $B - $C'
       passing 1 as A, 2 as B, 3 as C
       columns res number path '.'
     );

       RES
----------
         0

select * 
from xmltable(
       '$A + $B * $C'
       passing 1 as A, 2 as B, 3 as C
       columns res number path '.'
     );

       RES
----------
         7

Таким образом, вы можете легко выполнять вычисления динамического c, вам просто нужно добавить '$' к именам переменных:

with
data(a,b,c,d) as (
   select 1,1,1,1 from dual union all
   select 1,2,3,4 from dual union all
   select 5,5,5,5 from dual 
)
,calc(id, expression) as (
    select 1, 'A + B' from dual union all
    select 2, 'A + B - C' from dual union all
    select 3, 'A * B * C' from dual union all
    select 4, '(A + B) * C - D' from dual
)
select
   *
from
    data d
   ,calc c
   ,xmltable(
        (regexp_replace(c.expression,'(\w)','$\1'))
        passing
            d.A as A,
            d.B as B,
            d.C as C,
            d.D as D
        columns
            res number path '.'
   ) x;

         A          B          C          D         ID EXPRESSION             RES
---------- ---------- ---------- ---------- ---------- --------------- ----------
         1          1          1          1          1 A + B                    2
         1          1          1          1          2 A + B - C                1
         1          1          1          1          3 A * B * C                1
         1          1          1          1          4 (A + B) * C - D          1
         1          2          3          4          1 A + B                    3
         1          2          3          4          2 A + B - C                0
         1          2          3          4          3 A * B * C                6
         1          2          3          4          4 (A + B) * C - D          5
         5          5          5          5          1 A + B                   10
         5          5          5          5          2 A + B - C                5
         5          5          5          5          3 A * B * C              125
         5          5          5          5          4 (A + B) * C - D         45

12 rows selected.

PS Обратите внимание, перед знаком «-» нужно поставить пробел, иначе он будет считаться переменной «B-»:

SQL> select * from xmltable('$A+$B-$C' passing 1 as A, 2 as B, 3 as C columns res number path '.');
select * from xmltable('$A+$B-$C' passing 1 as A, 2 as B, 3 as C columns res number path '.')
                               *
ERROR at line 1:
ORA-19228: XPST0008 - undeclared identifier: prefix 'B-' local-name ''
...