How to calculate value of string in oracle? - oracle

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

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...

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 .

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.

You can use the xmlquery() function to implement it. Here is a sample code:
select
xmlquery(
replace( 'your variable', '/', ' div ')
returning content
).getNumberVal()
from
dual;
For example the code below
SELECT
XMLQUERY(
REPLACE( '3/4', '/', ' div ')
RETURNING CONTENT
).getNumberVal() FROM DUAL;
returns 0.75

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>

Related

If I am querying below query, getting error

Exec('select * from dual ' );
Showing invalid Sql query. Is it a valid query? If no, what could the reason and solution?
EXEC is a SQL*Plus command, used to run PL/SQL code (usually procedures).
But, if you insist on selecting from dual, no problem. Here's how: as it has to be PL/SQL, declare a variable and select into it. As DUAL has one column (named DUMMY), it'll work just fine:
SQL> var l_dum varchar2;
SQL> exec select * into :l_dum from dual;
PL/SQL procedure successfully completed.
SQL> print l_dum
L_DUM
--------------------------------
X
SQL>
What we normally do is
SQL> select * from dual;
D
-
X
SQL>
Your error? Single quotes, no variable to select into.
EXEC[UTE] IMMEDIATE must be used within an anonymous block or procedure.
For example:
Begin
Execute Immediate 'Select * From Dual';
End;
Here is a simple Youtube explanation:
https://youtu.be/47KzYVBNbIs

Oracle - How to execute a query with parameters?

I am new to Oracle and i am trying to execute a simple select with some parameters but i cant get it to work.
For
SELECT idl.column_value clientguid
FROM TableName idl
LEFT JOIN :ParamName_Type olt ON olt.clientguid = idl.column_value
WHERE (olt.flag = 0)
But declare does not work. I could not find any help on internet.
Thanks.
Oracle SQL Developer should handle variables the same way SQLPlus does, that is with the &.
For example ( in SQLPlus for simplicity):
SQL> select 1 from &tableName;
Enter value for tablename: dual
old 1: select 1 from &tableName
new 1: select 1 from dual
1
----------
1
What you can not do is use the parameter as a part of a table name, assuming that Developer "knows" which part is the parameter name and which one is the fixed part.
For example:
SQL> select * from &ParamName_Type;
Enter value for paramname_type:
that is, all the string ParamName_Type wil be interpreted as a variable name and substituited with the value you enter.
Also, consider that this is a client-specific behaviour, not an Oracle DB one; so, the same thing will not work in a different client (Toad for Oracle for example).
Consider that you are trying to use a "parameter" that represents a table name, and you only can do this by the means of some client, because plain SQL does not allow it.
If you need to do such a thing in some piece of code that has to work no matter the client, you need dynamic SQL
If you need something more complex, you may need some dynamic SQL; for example:
SQL> declare
2 vTableName varchar2(30) := '&table_name';
3 vSQL varchar2(100):= 'select 1 from ' || vTableName ||
' union all select 2 from ' || vTableName;
4 type tResult is table of number;
5 vResult tResult;
6 begin
7 execute immediate vSQL bulk collect into vResult;
8 --
9 -- do what you need with the result
10 --
11 for i in vResult.first .. vResult.last loop
12 dbms_output.put_line(vResult(i));
13 end loop;
14 end;
15 /
Enter value for table_name: dual
old 2: vTableName varchar2(30) := '&table_name';
new 2: vTableName varchar2(30) := 'dual';
1
2
PL/SQL procedure successfully completed.
SQL>

PL/SQL set a link as default at the begining of the script

I need to select a link at the beginning in the script. Usually we do select links as below,
begin
select * from v$database#linkname;
end;
But now I need to select the link at the beginning something like this,
begin
select_link 'linkname';
select * from v$database;
end;
Thank you!
select * from v$database#linkname;
You cannot simply have a SELECT statement like that in PL/SQL. It expects an INTO clause.
If I understand correct;y, you want to parameterize the DATABASE LINK. I am afraid you need to (ab) use dynamic SQL.
For example,
SQL> var cur refcursor
SQL> DECLARE
2 var_link varchar2(20);
3 BEGIN
4 var_link:='#your_db_link';
5 OPEN :cur FOR 'SELECT * FROM dual'||var_link;
6 END;
7 /
PL/SQL procedure successfully completed.
SQL> print cur
D
-
X
SQL>

executing a function in sql plus

I created a function in oracle that inserts records in specific tables and return an output according to what occurs within the function. e.g (ins_rec return number)
How do I call this function and see its output in sql plus
declare
x number;
begin
x := myfunc(myargs);
end;
Alternatively:
select myfunc(myargs) from dual;
One option would be:
SET SERVEROUTPUT ON
EXEC DBMS_OUTPUT.PUT_LINE(your_fn_name(your_fn_arguments));
As another answer already said, call select myfunc(:y) from dual; , but you might find declaring and setting a variable in sqlplus a little tricky:
sql> var y number
sql> begin
2 select 7 into :y from dual;
3 end;
4 /
PL/SQL procedure successfully completed.
sql> print :y
Y
----------
7
sql> select myfunc(:y) from dual;

How to return a resultset / cursor from a Oracle PL/SQL anonymous block that executes Dynamic SQL?

I have this table:
ALLITEMS
---------------
ItemId | Areas
---------------
1 | EAST
2 | EAST
3 | SOUTH
4 | WEST
The DDL:
drop table allitems;
Create Table Allitems(ItemId Int,areas Varchar2(20));
Insert Into Allitems(Itemid,Areas) Values(1,'east');
Insert Into Allitems(ItemId,areas) Values(2,'east');
insert into allitems(ItemId,areas) values(3,'south');
insert into allitems(ItemId,areas) values(4,'east');
In MSSQL, to get a cursor from a dynamic SQL I can do:
DECLARE #v_sqlStatement VARCHAR(2000);
SET #v_Sqlstatement = 'SELECT * FROM ALLITEMS';
EXEC (#v_sqlStatement); --returns a resultset/cursor, just like calling SELECT
In Oracle, I need to use a PL/SQL Block:
SET AUTOPRINT ON;
DECLARE
V_Sqlstatement Varchar2(2000);
outputData SYS_REFCURSOR;
BEGIN
V_Sqlstatement := 'SELECT * FROM ALLITEMS';
OPEN outputData for v_Sqlstatement;
End;
--result is : anonymous block completed
**But all I get is
anonymous block completed".
How do I get it to return the cursor?
(I know that if I do AUTOPRINT, it will print out the information in the REFCURSOR (it's not printing in the code above, but thats another problem))
I will be calling this Dynamic SQL from code (ODBC,C++), and I need it to return a cursor. How?
You can write a PL/SQL function to return that cursor (or you could put that function in a package if you have more code related to this):
CREATE OR REPLACE FUNCTION get_allitems
RETURN SYS_REFCURSOR
AS
my_cursor SYS_REFCURSOR;
BEGIN
OPEN my_cursor FOR SELECT * FROM allitems;
RETURN my_cursor;
END get_allitems;
This will return the cursor.
Make sure not to put your SELECT-String into quotes in PL/SQL when possible. Putting it in strings means that it can not be checked at compile time, and that it has to be parsed whenever you use it.
If you really need to use dynamic SQL you can put your query in single quotes:
OPEN my_cursor FOR 'SELECT * FROM allitems';
This string has to be parsed whenever the function is called, which will usually be slower and hides errors in your query until runtime.
Make sure to use bind-variables where possible to avoid hard parses:
OPEN my_cursor FOR 'SELECT * FROM allitems WHERE id = :id' USING my_id;
in SQL*Plus you could also use a REFCURSOR variable:
SQL> VARIABLE x REFCURSOR
SQL> DECLARE
2 V_Sqlstatement Varchar2(2000);
3 BEGIN
4 V_Sqlstatement := 'SELECT * FROM DUAL';
5 OPEN :x for v_Sqlstatement;
6 End;
7 /
ProcÚdure PL/SQL terminÚe avec succÞs.
SQL> print x;
D
-
X
You should be able to declare a cursor to be a bind variable (called parameters in other DBMS')
like Vincent wrote, you can do something like this:
begin
open :yourCursor
for 'SELECT "'|| :someField ||'" from yourTable where x = :y'
using :someFilterValue;
end;
You'd have to bind 3 vars to that script. An input string for "someField", a value for "someFilterValue" and an cursor for "yourCursor" which has to be declared as output var.
Unfortunately, I have no idea how you'd do that from C++. (One could say fortunately for me, though. ;-) )
Depending on which access library you use, it might be a royal pain or straight forward.
This setting needs to be set:
SET SERVEROUTPUT ON

Resources