"Need help writing the query for below logic."
This is not a problem which can be solved in pure SQL, because:
- executing the calculation string requires dynamic SQL
- you need recursion to look up records and evaluate the results
Here is a recursive function which produces the answers you expect. It has three private procs so that the main body of the function is simple to understand. In pseudo-code:
- look up record
- if record is
value then return it and exit
- else explode
calculation
- recurse 1, 3, 4 for each part of exploded
calculation until 2
Apologies for the need to scroll:
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;
/
Run like this:
SQL> select dyn_calc(6) from dual;
DYN_CALC(6)
-----------
20
SQL>
or, to get the output exactly as you require:
select id, calculation, dyn_calc(id) as value
from t23
where calculation is not null;
Notes
- There is no exception handling. If the data is invalid the function will just blow up
- the
split_calc() proc uses translate() to extract the operator rather than regex. This is because regexp_substr(p_calc, '[\-\+\*\%]', 1, 1) mysteriously swallows the -. This appears to be an environment-related bug. Consequently extending this function to process 1+4+2 will be awkward.
Here is a LiveSQL demo.