在oracle sql查询中需要有关动态计算的帮助

时间:2018-01-10 03:36:16

标签: sql oracle

我有一个表格tab_1,其中包含以下值。

ID Calculation value
1                10
2                10
3    1+2         
4                 5
5    3-2          
6    5+1

需要帮助编写以下逻辑的查询。我有一个表,其中记录包含计算字符串或计算中使用的值。我需要像这样解析calculation

ID 3 is the sum of ID 1 and 2.
ID 5 is the minus of ID 3 and 2.
ID 6 is the sum of ID 5 and 1.

然后我需要为引用的ID选择记录并执行计算。我的 预期产出:

ID Calculation value
3    1+2         20
5    3-2         10
6    5+1         20

谢谢 - 纳尼

2 个答案:

答案 0 :(得分:3)

  

"需要帮助编写以下逻辑的查询。"

这不是可以在纯SQL中解决的问题,因为:

  • 执行计算字符串需要动态SQL
  • 您需要递归来查找记录并评估结果

这是一个递归函数,可以产生您期望的答案。它有三个私有过程,因此函数的主体很容易理解。在伪代码中:

  1. 查找记录
  2. 如果记录为value,则返回并退出
  3. else explode calculation
  4. 为爆炸calculation的每个部分递归1,3,4,直至2
  5. 需要滚动的道歉:

    create or replace function dyn_calc
         (p_id in number)
          return number
    is 
        result number;
        n1 number;
        n2 number;
        l_rec t23%rowtype;
        l_val number;
    
        type split_calc_r is record (
            val1 number
            , operator varchar2(1)
            , val2 number
        );
        l_calc_rec split_calc_r;
    
        function get_rec
            (p_id in number)
            return t23%rowtype
        is 
            rv t23%rowtype;
        begin
            select *
            into rv   
            from t23
            where id = p_id;
            return rv;
        end get_rec;    
    
        procedure split_calc
           (p_calc in varchar2
            , p_n1 out number
            , p_n2 out number
            , p_operator out varchar2)
        is
        begin
             p_n1 := regexp_substr(p_calc, '[0-9]+', 1, 1);
             p_n2 := regexp_substr(p_calc, '[0-9]+', 1, 2);
             p_operator := translate(p_calc, '-+*%01923456789','-+*%'); --regexp_substr(p_calc, '[\-\+\*\%]', 1, 1);
        end split_calc;
    
        function exec_calc 
            (p_n1 in number
              , p_n2 in number
              , p_operator in varchar2)
            return number
        is 
            rv number;
        begin
            execute immediate
                'select :n1 ' ||  p_operator ||  ' :n2 from dual'
                into rv
                using p_n1, p_n2; 
            return rv;
        end exec_calc;    
    
    begin
        l_rec := get_rec(p_id);
    
        if l_rec.value is not null then
            result := l_rec.value;
        else        
             split_calc(l_rec.calculation
                         , l_calc_rec.val1
                         , l_calc_rec.val2
                         , l_calc_rec.operator);
             n1 := dyn_calc (l_calc_rec.val1);
             n2 := dyn_calc (l_calc_rec.val2);
             result := exec_calc(n1, n2, l_calc_rec.operator);
        end if;
    
        return result;
    end;
    /
    

    像这样跑:

    SQL>  select dyn_calc(6) from dual;
    
    DYN_CALC(6)
    -----------
    20
    
    SQL>
    

    或者,要完全按照您的要求获得输出:

    select id, calculation, dyn_calc(id) as value
    from t23
    where calculation is not null;
    

    备注

    • 没有异常处理。如果数据无效,则功能将会爆炸
    • split_calc() proc使用translate()来提取运算符而不是正则表达式。这是因为regexp_substr(p_calc, '[\-\+\*\%]', 1, 1)神秘地吞噬了-。这似乎是一个与环境有关的错误。因此,将此功能扩展到流程1+4+2将会很尴尬。

    这是a LiveSQL demo

答案 1 :(得分:1)

在SQL中:

select 'ID ' +ID+ ' is the ' + case when calculation like '%-%' then ' minus '
when calculation like '%+%' then ' sum ' END +' of  
ID'+replace(replace(calculation,'+',' and '),'-',' and ')
from tab_1
where calculation is not null

在Oracle中:

select 'ID ' ||ID|| ' is the ' || case when calculation like '%-%' then ' minus '
when calculation like '%+%' then ' sum ' END|| ' of 
ID'||replace(replace(calculation,'+',' and '),'-',' and ')
from tab_1
where calculation is not null