PLSQL Oracle 10 - executing a stored proc - oracle

I'm trying to execute a stored procedure, but I'm not sure if my syntax is wrong or not.
set dbms_output.put_line on;
declare
v_premnum NUMBER(10);
v_util_type CHAR(10);
v_result VARCHAR2(200);
Begin
execute myprocedure( 'E', v_util_type, 73105 , v_premnum);
dbms_output.put_line = v_result
end;
/

There are two ways. Either your procedure has an output parameter:
declare
v_premnum NUMBER(10) := 1234;
v_util_type CHAR(10) := 'the type';
v_result VARCHAR2(200);
begin
myprocedure('E', v_util_type, 73105 , v_premnum, v_result);
dbms_output.put_line(v_result);
end;
Or it should be a function returning the desired value:
declare
v_premnum NUMBER(10) := 1234;
v_util_type CHAR(10) := 'the type';
v_result VARCHAR2(200);
begin
v_result := myfunction('E', v_util_type, 73105 , v_premnum);
dbms_output.put_line(v_result);
end;

Related

Oracle PL/SQL - Dereference a string as a variable

Is it possible to dereference a string as a variable in PL/SQL?
I'm looking for something like this:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
-- This of course doesn't work, it's just to illustrate what I'm looking for:
DBMS_OUTPUT.PUT_LINE(&my_var_ref) -- Prints test
end;
Pass the name as a procedure parameter:
declare
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
begin
my_func(&my_var_ref) -- Pass my_var instead of my_var_ref
end;
[TL;DR] No, you cannot dereference a PL/SQL variable. However, an alternative option might be to use an associative array.
If you try to dereference it using EXECUTE IMMEDIATE then the PL/SQL block that is being dynamically evaluated has no knowledge of the context from the calling block so cannot get the value of the dereferenced variable.
For example:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ' || my_var_ref || '; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
Outputs:
BEGIN :value := my_var; END;
ORA-06550: line 1, column 17:
PLS-00201: identifier 'MY_VAR' must be declared
It has got the correct variable name but the variable is not defined in the context within which the dynamic evaluation of the PL/SQL block is occurring so it doesn't work.
However, if you try to pass in the variable's value (rather than trying to dereference the variable) then this demonstrates that, apart from dereferencing, the rest of the code would work:
DECLARE
my_var CONSTANT varchar2(50) := 'test';
my_var_ref CONSTANT varchar2(50) := 'my_var';
value VARCHAR2(50);
plsql_block VARCHAR2(100) := 'BEGIN :value := ''' || my_var || '''; END;';
BEGIN
DBMS_OUTPUT.PUT_LINE( plsql_block );
EXECUTE IMMEDIATE plsql_block USING IN OUT value;
DBMS_OUTPUT.PUT_LINE( value );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE( SQLERRM );
END;
/
Outputs:
BEGIN :value := 'test'; END;
test
However, you could use a PL/SQL associative array instead:
DECLARE
TYPE MAP IS TABLE OF VARCHAR2(50) INDEX BY VARCHAR2(50);
my_var_ref CONSTANT VARCHAR2(50) := 'my_var';
v_map MAP;
BEGIN
v_map('my_var') := 'test';
DBMS_OUTPUT.PUT_LINE( v_map( my_var_ref) );
END;
/
Which outputs:
test
db<>fiddle here
You can using packages.
create or replace package test_pkg as
my_var1 varchar2(50);
my_var2 varchar2(50);
my_var3 varchar2(50);
procedure set_val(p_var in varchar2,
p_val in varchar2);
function get_val(p_var in varchar2)
return varchar2;
end test_pkg;
/
create or replace package body test_pkg as
procedure set_val(p_var in varchar2,
p_val in varchar2) is
begin
execute immediate 'begin
test_pkg.' || p_var || ' := :x;
end;'
using p_val;
end set_val;
function get_val(p_var in varchar2)
return varchar2 is
v_value varchar2(50);
begin
execute immediate 'begin
:x := test_pkg.' || p_var || ';
end;'
using out v_value;
return v_value;
end get_val;
end test_pkg;
/
Then
set serveroutput on
begin
for i in 1 .. 3 loop
test_pkg.set_val('my_var' || i, 'Test ' || i);
end loop;
for i in 1 .. 3 loop
dbms_output.put_line('my_var' || i || ' = ' || test_pkg.get_val('my_var' || i));
end loop;
end;
Output:
my_var1 = Test 1
my_var2 = Test 2
my_var3 = Test 3

how to catch the error of execute immediate (open for)?

I have this procedure:
PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR)
IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
v_sql := 'BEGIN OPEN :1 FOR :2 ';
v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
v_sql := v_sql||' USING '||v_bind_vars||'; ';
--tried also following but also couldn't catch the error!
--v_sql := v_sql ||'EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(''error: ''||SQLCODE||'' - ''||SQLERRM); END;';
v_sql := v_sql||' END;';
v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';
EXECUTE IMMEDIATE v_sql using P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM); -- this part is not catching the error!!!!!
END;
Sometimes, the script will throw an error like:
ORA-12847: retry parsing due to concurrent DDL operation
[Error] Execution (1: 1): ORA-12847: retry parsing due to concurrent DDL operation
My question is: how to catch that error?
You cannot bind object names (e.g. cursor names) and variable names into dynamic SQL, only values. I think this may do what you intend:
PROCEDURE proc_with_cursor( p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
v_script VARCHAR2 (32767);
BEGIN
v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';
OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('error: '||sqlcode||' - '||sqlerrm);
END;
I don't understand your problem. If you have this procedure
CREATE OR REPLACE PROCEDURE proc_with_cursor( p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
v_script VARCHAR2 (32767);
BEGIN
v_script := 'select sysdate fromM dual where 1= :bind_first and 2 = :bindsecond';
OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;
END;
Then you get this:
DECLARE
cur SYS_REFCURSOR;
BEGIN
proc_with_cursor(1, 2, cur);
end;
/
Error at line 1
ORA-00923: FROM keyword not found where expected
ORA-06512: at "xxx.PROC_WITH_CURSOR", line 6
ORA-06512: at line 4
What else would you like to get? Your (poor) code is working:
CREATE OR REPLACE PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
v_sql := 'BEGIN OPEN :1 FOR :2 ';
v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
v_sql := v_sql||' USING '||v_bind_vars||'; ';
v_sql := v_sql||' END;';
v_script := 'select sysdate fromm dual where 1= :bind_first and 2 = :bindsecond';
EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);
END;
DECLARE
cur SYS_REFCURSOR;
BEGIN
proc_with_cursor(1,2, cur);
END;
Prints error: -923 - ORA-00923: FROM keyword not found where expected on the DBMS_OUTPUT.
If you like to get the exception then do
CREATE OR REPLACE PROCEDURE proc_with_cursor( P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
v_sql VARCHAR2 (32767);
v_script VARCHAR2 (32767);
v_bind_vars VARCHAR2 (32767);
BEGIN
...
EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);
RAISE;
END;

Read file and generate query in plsql oracle 11

I am writing a stored procedure where I have to do following: I want to have a file (any format properties, json, xml) which will have information of which columns I want to extract from my table.
For example: my table has columns A,B,C,D,E, and suppose my file.properties has below information
A=1
B=0
C=1
D=1
F=0
So my generated query should be Select A,C,D from my table;
How can I do this in Oracle 11G?
I think you need this
SQL> set serveroutput on;
SQL> create or replace procedure pr_dynamic_sql( v_result out sys_refcursor ) is
v_outfile utl_file.file_type;
v_path varchar2(100) := 'UTL_FILE_DIR';
-- alias for the directory where your text files generated at OS.
v_row varchar2(100);
v_file varchar2(100);
v_letter varchar2(10);
v_number varchar2(10);
v_sql varchar2(100):= 'select ';
begin
v_file := 'myfile.properties';
v_outfile := utl_file.fopen(v_path, v_file, 'r');
loop
begin
utl_file.get_line(v_outfile,v_row);
v_letter := regexp_substr(v_row,'[^=]');
v_number := substr(regexp_substr(v_row,'[^=]+$'),1,1);
if v_number = '1' then
v_sql := v_sql||v_letter||',';
end if;
exception when no_data_found then exit;
end;
end loop;
utl_file.fclose(v_outfile);
v_sql := rtrim(v_sql,',')||' from mytable';
open v_result for v_sql;
end;
and call
SQL> begin
pr_dynamic_sql(v_result => :v_result);
end;
/
to get results as of cursor type.

Dynamic select execution missing expression error

I am using Oracle 12, and I want to make a dynamic procedure which selects rows from specific table but according to an unknown conditio. That condition will be specified as input parameter.
Suppose I have a column called employee id and I want to call the procedure
with the following condition
execute s('employeeid = 2')
My code is
create or replace procedure s (condition varchar)
as
TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type
emp_cv EmpCurTyp; -- declare cursor variable
my_ename VARCHAR2(15);
my_sal NUMBER := 2;
mycondition varchar2(100):=condition;
BEGIN
OPEN emp_cv FOR -- open cursor variable
'SELECT employeeid, employeename FROM employees WHERE = :s' USING mycondition;
END;
but I am getting an error
missing expression
What am I doing wrong, and will the result of this procedure be selected rows from employees table that satisfy applied condition ?
The USING is meant to handle values, not pieces of code; if you need to edit your query depending on an input parameter ( and I believe this is a very dangerous way of coding), you should treat the condition as a string to concatenate to the query.
For example, say you have this table:
create table someTable(column1 number)
This procedure does somthing similar to what you need:
create or replace procedure testDyn( condition IN varchar2) is
cur sys_refcursor;
begin
open cur for 'select column1 from sometable where ' || condition;
/* your code */
end;
Hot it works:
SQL> exec testDyn('column1 is null');
PL/SQL procedure successfully completed.
SQL> exec testDyn('column99 is null');
BEGIN testDyn('column99 is null'); END;
*
ERROR at line 1:
ORA-00904: "COLUMN99": invalid identifier
ORA-06512: at "ALEK.TESTDYN", line 4
ORA-06512: at line 1
This is not embedded in a procedure yet but I tested this and works:
DECLARE
TYPE OUT_TYPE IS TABLE OF VARCHAR2 (20)
INDEX BY BINARY_INTEGER;
l_cursor INTEGER;
l_fetched_rows INTEGER;
l_sql_string VARCHAR2 (250);
l_where_clause VARCHAR2 (100);
l_employeeid VARCHAR2 (20);
l_employeename VARCHAR2 (20);
l_result INTEGER;
o_employeeid OUT_TYPE;
o_employeename OUT_TYPE;
BEGIN
l_cursor := DBMS_SQL.OPEN_CURSOR;
l_sql_string := 'SELECT employeeid, employeename FROM employees WHERE ';
l_where_clause := 'employeeid = 2';
l_sql_string := l_sql_string || l_where_clause;
DBMS_SQL.PARSE (l_cursor, l_sql_string, DBMS_SQL.V7);
DBMS_SQL.DEFINE_COLUMN (l_cursor,
1,
l_employeeid,
20);
DBMS_SQL.DEFINE_COLUMN (l_cursor,
2,
l_employeename,
20);
l_fetched_rows := 0;
l_result := DBMS_SQL.EXECUTE_AND_FETCH (l_cursor);
LOOP
EXIT WHEN l_result = 0;
DBMS_SQL.COLUMN_VALUE (l_cursor, 1, l_employeeid);
DBMS_SQL.COLUMN_VALUE (l_cursor, 2, l_employeename);
l_fetched_rows := l_fetched_rows + 1;
o_employeeid (l_fetched_rows) := l_employeeid;
o_employeename (l_fetched_rows) := l_employeename;
l_result := DBMS_SQL.FETCH_ROWS (l_cursor);
END LOOP;
DBMS_SQL.CLOSE_CURSOR (l_cursor);
DBMS_OUTPUT.PUT_LINE (o_employeeid (1));
DBMS_OUTPUT.PUT_LINE (o_employeename (1));
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE ('GENERAL FAILURE: ' || SQLERRM);
END;

Working with dbms_lob.copy and error ORA-06502:

I am bit lost with working with dbms_lob.copy
CREATE OR REPLACE PROCEDURE Ex_PRC IS
dest_lob CLOB;
src_lob CLOB;
BEGIN
SELECT F_CLOB INTO dest_lob
FROM EX_EMPLOYEE
WHERE id = 1;
dbms_lob.copy (dest_lob, src_lob, 30, 1, 1);
COMMIT;
END;
/
I got error
numeric or value error invalid lob locator specified ora-22275
I followed up this SO answer because thats what I needed is to split the blob and move them .but I didnt understand why he used dbms_lob.createtemporary
set serveroutput on
create or replace procedure test_clob (p_clob_res out clob) is
cursor c_tabs is
select ename from emp;
v_clob clob;
amt integer := 0;
begin
dbms_lob.createtemporary(v_clob,true,dbms_lob.session);
for r_tabs in c_tabs
loop
dbms_lob.writeappend(v_clob,length(r_tabs.ename)+1,r_tabs.ename||' ');
amt := amt + length(r_tabs.ename);
end loop;
p_clob_res := v_clob;
end test_clob;
/
create or replace procedure call_clob is
p_clob clob;
my_buff varchar2 (2000);
amt binary_integer := 2000;
begin
test_clob(p_clob);
my_buff := dbms_lob.substr(p_clob,amt,1);
dbms_output.put_line(my_buff);
end call_clob;
/
begin
call_clob();
end;
/

Resources