sql - 需要oracle sql查询中动态计算的帮助

标签 sql oracle

我有一个表 tab_1,其值如下。

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

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

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

谢谢——纳尼

最佳答案

"Need help writing the query for below logic."

这不是一个可以用纯 SQL 解决的问题,因为:

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

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

  1. 查找记录
  2. 如果记录是,则返回它并退出
  3. 否则爆炸计算
  4. 对分解计算的每个部分递归1、3、4,直到2

抱歉需要滚动:

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() 过程使用 translate() 来提取运算符而不是正则表达式。这是因为 regexp_substr(p_calc, '[\-\+\*\%]', 1, 1) 神秘地吞掉了 -。这似乎是一个与环境相关的错误。因此,扩展这个函数来处理1+4+2将会很尴尬。

这是a LiveSQL demo

关于sql - 需要oracle sql查询中动态计算的帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48179927/

相关文章:

sql - 我如何知道 CONSTRAINT_NAME 是主键还是外键?

SQL查找列中的组合

oracle - 使用ODI将多个定界文件合并到Hive

oracle - 在 Oracle 中对一行进行 sha1 哈希

forms - 神谕按钮问题

mysql - "exists row with specific values A and B or no row with value A at all"的 SQL 语句

sql - 如何按文本数据类型排序

c# - 如何执行 ALTER TABLE 查询?

java - 从浏览器小程序使用 JDBC 时为 "access denied"

database - Liquibase 锁 - 原因?