tags:

views:

256

answers:

4

Hi If I have a string say "3*2+24" how can calculate its value in Oracle? In sql server you can do exec ('select 3*2+24') and it returns 30

Thanks

+2  A: 

In ORACLE you can do any computation you want using the dual feature. For example

SELECT 3*3-(2+2) FROM DUAL

However, you cannot do

SELECT '3*3-(2+2)' FROM DUAL

Because it will just return the string of '3*3-(2+2)'. If all you have is a string, I would probably strip it out into a numeric function then do the calculation.

northpole
What about TO_NUMBER? I haven't found anything conclusive about whether or not it would work on an expression, hence why this isn't an answer. But it's worth a shot in your SQL*Plus or whatever environment: `select to_number('3*3-(2+2)') from dual`
Platinum Azure
SQL> SELECT to_number('2*6*10') FROM dual; SELECT to_number('2*6*10') FROM dual ORA-01722: invalid number SQL>
DCookie
Thanks, northpole. I haven't registered yet to be able to vote for answers, but i'll do it later.I tried select to_number('3*3-(2+2)') from dual and got an error: Invalid number
ya, you get the invalid number because of the computation symbols. You will have to strip each character out and form a numeric math formula to get that to work.
northpole
A: 

It's a bit clunkier in Oracle but it can be done.

SQL> set serveroutput on
SQL> declare
  2     str varchar2(250) := '3*2+24';
  3     n number;
  4  begin
  5    execute immediate 'select '||str||' from dual' into n;
  6    dbms_output.put_line(str||' = '||to_char(n)||' !!');
  7  end;
  8  /

3*2+24 = 30 !!

PL/SQL procedure successfully completed.

SQL>
APC
+1  A: 

Here's a little function to calculate arbitrary strings of arithmetic:

SQL> CREATE OR REPLACE FUNCTION calc(pi_val VARCHAR2) RETURN NUMBER IS
  2  v_return NUMBER;
  3  BEGIN
  4    EXECUTE IMMEDIATE 'select '||pi_val||' from dual' INTO v_return;
  5    RETURN v_return;
  6  END;
  7  /

Function created
SQL> SELECT calc('2*6*10') FROM dual;

CALC('2*6*10')
--------------
           120

SQL>

Obviously, for production purposes you'd need some error handling...

DCookie
It's also extremely vulnerable to a SQL injection attack for production logic.
Steve Broberg
Read my answer for the possibility of an sql injection attacks.
tuinstoel
+1  A: 

You can use DCookie's solution.

You can decrease the possibility of an sql injection attack by creating a new user without privileges.

Log in as system and create a new user without privileges:

create user new_user identified by password_new_user;

Create the function (as system) in schema new_user.

create or replace function new_user.calc(pi_val varchar2) return number
is
  v_return number;
begin
  execute immediate  'select '||pi_val||' from dual' INTO v_return;
  return v_return;
end;
/

Next grant execute privileges (as system) on function new_user.calc to the relevant Oracle users (for instance tuinstoel (that's me)).

grant execute on new_user.calc to tuinstoel;

Log in as user tuinstoel.

connect tuinstoel/cheese_and_cheese@ora11

SQL> select new_user.calc('2+3') from dual;

NEW_USER.CALC('2+3')
--------------------
                   5

Everyone who calls the function new_user.calc has the privileges of new_user (none) inside function new_user.calc, not the rights of the caller (definer's privileges not invoker's privileges).

When you don't want to include new_user. in every call to calc do as tuinstoel:

 create synonym calc for new_user.calc;

Next you can test this with:

SQL> select calc('2+3') from dual;

CALC('2+3')
-----------
          5

edit1: Others have contemplated about this solution and they have pointed out some (potential) problems: See http://forums.oracle.com/forums/thread.jspa?forumID=75&threadID=943576 .

tuinstoel
"has the privileges of new_user (none)" It's amazing how many privileges are granted to PUBLIC in Oracle. If the input isn't sanitized (eg reject it if there are any quotes or alphabetic characters) it would be pretty dangerous.
Gary
@Gary, well show us an example of what can go wrong?
tuinstoel