Calling preocedure by passing DB Link Dynamically - oracle

How to pass db link dynamically while calling a procedure?
Execute immediate will work or we need to use dbms_sql?
For DBMS_SQL i seen it used mostly with curosrs :(
Can any one help me ?

You can use EXECUTE IMMEDIATE. Something like
DECLARE
l_dblink_name VARCHAR2(30) := 'YourDBLink';
l_sql_stmt VARCHAR2(1000);
BEGIN
l_sql_stmt := 'BEGIN procedure_name#' || l_dblink_name || ' (:1, :2); END;';
EXECUTE IMMEDIATE l_sql_stmt
USING 17, 42;
END;
assuming that your procedure takes two parameters and you want to call it with parameter values 17 and 42.

Related

ORA-01008: not all variables bound - "not all variables bound"

This is my plsql block, dynamic SQL. I can't find a reason why it comes up with an error 'no ORA-01008: not all variables bound ORA-06512: at line 23'.
I can't find the error on my EXECUTE IMMEDIATE statement.
DECLARE
form_name VARCHAR2(225) := 'MUST AS';
ad_no VARCHAR2(225) := :ad_no;
sql_stmt VARCHAR2(4000);
sql_output VARCHAR2(4000);
db_table VARCHAR(225) := inp_reminder_pkg.form_db_table(form_name);
col_id VARCHAR(225) := inp_reminder_pkg.get_col_id(form_name);
BEGIN
sql_stmt := '
SELECT :1
FROM #tableName
WHERE advno = :2
AND created = ( SELECT MAX(CREATED)
FROM #tableName
WHERE advno = :2 )'
;
sql_stmt := replace(sql_stmt, '#tableName', db_table);
EXECUTE IMMEDIATE sql_stmt
INTO sql_output
USING col_id, ad_no;
dbms_output.put_line(sql_output);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('no-data');
END;
Let me know what I am missing. thanks you
There are three bind variables (even though two have the same name), you need to send 3 arguments for them in the execute immediate statement.
Note that you probably didn’t mean for the column name to be input as a bind variable, this is something that has to be dynamically executed if you want to have a variable column being selected.
There are two problems with your code:
The dynamic query has two instances of the placeholder :advno so you need to pass two values in the USING clause. Yes this is a bit rubbish, but I guess Oracle felt parsing dynamic SQL is hard enough without asking the compiler to match placeholder names.
We can't pass column names or other identifiers as parameters. We have to break up the statement to reference the column name variable. For the same reason you have the replace() call to substitute the table name.
So you need to change your procedure so it looks like this:
DECLARE
form_name VARCHAR2(225) := 'MUST AS';
ad_no VARCHAR2(225) := :ad_no;
sql_stmt VARCHAR2(4000);
sql_output VARCHAR2(4000);
db_table VARCHAR(225) := inp_reminder_pkg.form_db_table(form_name);
col_id VARCHAR(225) := inp_reminder_pkg.get_col_id(form_name);
BEGIN
sql_stmt := '
SELECT ' || col_id || '
FROM #tableName
WHERE advno = :2
AND created = ( SELECT MAX(CREATED)
FROM #tableName
WHERE advno = :2 )'
;
sql_stmt := replace(sql_stmt, '#tableName', db_table);
EXECUTE IMMEDIATE sql_stmt
INTO sql_output
USING ad_no, ad_no;
dbms_output.put_line(sql_output);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('no-data');
END;

Oracle display resultset of dynamic sql

i am pretty new to oracle and i am searching for two days already for a solution for my problem.
i have a view which should have a dynamic column and table name.
something like that:
DECLARE
plsql_block VARCHAR2(500);
BEGIN
plsql_block := 'SELECT CONCAT('some','column') FROM CONCAT('some','table')';
EXECUTE IMMEDIATE plsql_block
END;
This would work but how to i display the result? I already tried it with DBMS.Output and a Loop but thats not exactly what i want. i need that it is displayed as a normal result set in the GUI when i run this command. Does anyone has a hint for me how i am doing this in oracle?
I am Thankful for every answer
Thanks pat
Actually I don't understand your dynamic query. But as per my understanding this query is multirow result result set. So you need to use BULK collect and iterate throuh the output for just the purpose of display.
There are two approaches
1) Just to display the output.
SET serveroutput ON;
DECLARE
plsql_block VARCHAR2(500);
lv_col1 VARCHAR2(10):='1';
lv_col2 VARCHAR2(10):='2';
type tab_var
IS
TABLE OF VARCHAR2(10);
tab tab_var;
BEGIN
plsql_block := 'SELECT CONCAT('||lv_col1||','||lv_col2||') FROM dual';
EXECUTE immediate plsql_block bulk collect INTO tab;
FOR i IN tab.first..tab.last
LOOP
dbms_output.put_line(tab(i));
END LOOP;
END;
2) Approach will be refactor this into a function and then use it as below.
Creating a Table Type
create or replace
type string_table
IS TABLE OF VARCHAR2(100);
CREATE OR REPLACE
FUNCTION func_mu
RETURN string_table
AS
plsql_block VARCHAR2(500);
lv_col1 VARCHAR2(10):='1';
lv_col2 VARCHAR2(10):='2';
tab string_table;
BEGIN
plsql_block := 'SELECT CONCAT('||lv_col1||','||lv_col2||') FROM dual';
EXECUTE immediate plsql_block bulk collect INTO tab;
RETURN tab;
END;
SELECT * FROM TABLE(func_mu);
If you are on Oracle 12c (with the corresponding Oracle client), you can do this:
declare
l_resultset sys_refcursor;
l_sql_text varchar2(500) :=q'{select 'Hello, 12c!' as greeting from dual}';
begin
open l_resultset for l_sql_text;
dbms_sql.return_result(l_resultset);
end;
(Untested, because I'm not near a 12c command line right now.)

Pl/sql Executing procedures

I am totally new to PL/SQL.
create or replace procedure p1(a in customer.id%type,
b out customer.name%type,
c out customer.dept%type)
is
begin
select name,dept into b,c from customer where id=a;
end;
Its created properly.
But I am not sure how to execute it.
EXEC p1(1);
But this is showing error.
Your procedure has three parameters so you'd need to call it with three parameters. In the case of OUT parameters, you need to pass in variables that will hold the values that are being returned by the procedure.
DECLARE
l_id customer.id%type := 1;
l_name customer.name%type;
l_dept customer.dept%type;
BEGIN
p1( l_id, l_name, l_dept );
<<do something with l_name and l_dept>>
END;
/
There are two ways to execute a procedure.
From the SQL prompt.
EXECUTE [or EXEC] procedure_name;
Within another procedure – simply use the procedure name.
procedure_name;
the procedure have 3 parameters, you can't call it like p1(1) using just one parameter
in your case try something like this
DECLARE
p_name customer.name%type;
p_department customer.dept%type;
BEGIN
p1(1, p_name, p_department);
END;
Output parameters should be stored in variables.
Input, can be variables or directly given in between the ( )
Use dbms_output.put_line to easily show output in your IDE.
DECLARE
p_name customer.name%type;
p_department customer.dept%type;
p_id customer.id%type := 1;
BEGIN
p1(p_id, p_name, p_department);
END;

using EXECUTE IMMEDIATE with multiple same bind arguments

When I create the following procedure
create or replace procedure check_exec_imm(
tab IN VARCHAR2,
col IN VARCHAR2,
col_name IN VARCHAR2
)
IS
cv SYS_REFCURSOR;
col_value VARCHAR2(32767);
lv_query VARCHAR2(32767);
BEGIN
lv_query := 'SELECT ' ||col||
' FROM ' ||tab||
' WHERE (:1 = ''EUR'' OR :1 = ''USD'') and rownum <=1';
EXECUTE IMMEDIATE lv_query INTO col_value USING col_name ;
DBMS_OUTPUT.PUT_LINE('COLUMN VALUE : ' || col_value);
END;
When the procedure is executed, I'm getting the following error
ORA-01008: not all variables bound
ORA-06512: at "GRM_IV.CHECK_EXEC_IMM", line 18
ORA-06512: at line 2
When I give the bind argument col_name again as below, the procedure is running fine.
EXECUTE IMMEDIATE lv_query INTO col_value USING col_name, col_name ;
Why oracle is behaving differently in this procedure. Since, it is the same bind variable, one bind argument should be sufficient right..!!? Please explain where I'm getting my logic wrong.
There is "special" behaviour in Oracle: Repeated Placeholder Names in Dynamic SQL Statements
In an Anonymous Block or CALL Statement it is not required to repeat the bind values if the names are equal.
For example this Anonymous Block is working:
DECLARE
a NUMBER := 4;
b NUMBER := 7;
plsql_block VARCHAR2(100);
BEGIN
plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END;';
EXECUTE IMMEDIATE plsql_block USING a, b; -- calc_stats(a, a, b, a)
END;
/
But this EXECUTE IMMEDIATE plsql_block USING a, b; does not work inside a Procedure.
The way you have referenced the column name through bind variable is not a preferred method as Nichoas pointed out. What you tried is called as native dynamic SQL using 'cleverer' bind variables.
In this method, you need to bind every parameter X times since you use it X times because they are all treated as separate variables.
Read more on binding to dynamic SQL.
#ethan and #ManiSankar I too had a same problem in my scenario as well. I solved this using some kind of brute force techinque. What i have done is
Before this
EXECUTE IMMEDIATE lv_query INTO col_value USING col_name ;
I have added replace condition in my code by replacing parameter with the required value then called "Execute Immediate" without "using" clause
lv_query := replace(lv_query, ':1',col_name);
EXECUTE IMMEDIATE lv_query INTO col_value;
I don't know this is optimal one but served purpose for what i am expecting..
Please advice if this one recommended or not...

Oracle EXECUTE IMMEDIATE error

There is UserA and UserB in my oracle.
This is the package from UserA:
CREATE OR REPLACE PACKAGE BODY pkgA AS
PROCEDURE procA
AS
l_sql = 'BEGIN ' || UserB.procB || (:l_v1,:l_v2) END;';
EXECUTE IMMEDIATE l_sql USING IN l_v1,IN l_v2;
END;
Thie procB is come from UserB;
When I run this, I get the error:
PLS-00201:IDENTIFIER 'UserB.procB' must be declared;
User A need the EXECUTE right on the userb.procB.
grant the right as User B:
grant execute on UserB.procB to userA;
Unless it's supplied as a parameter, the procedure name needs to be inside the string as a fixed value; you have it outside so it's trying to be interpreted as a variable name, which doesn't exist:
l_sql = 'BEGIN UserB.procB(:l_v1,:l_v2) END;';
But then you wouldn't need to execut it dynamically anyway, you could just do:
PROCEDURE ProcA AS
BEGIN
UserB.procB(l_v1, l_v2);
END;
If you were passing the procedure as a variable, which would be a little odd, you'd have something like:
PROCEDURE procA (proc_name in varchar2) AS
BEGIN
l_sql = 'BEGIN ' || proc_name || '(:l_v1,:l_v2) END;';
EXECUTE IMMEDIATE l_sql USING IN l_v1,IN l_v2;
END;
... and you'd call that as procA('UserB.procB'). I don't think that's what you're trying to do, but it isn't entirely clear.
In both cases you don't seem to have l_v1 or l_v2 defined, so I guess you've just missed that part of the code out.

Resources