Unable to pass a fetched date dynamically to PL/SQL execute immediate - oracle

I'm trying to pass a fetched date to a query that i'm using inside the execute immediate but i'm getting the following error:
"DATE_X" : invalid identifier
This is my code:
declare
DATE_X DATE;
begin
SELECT to_date(value, 'YYYY-MM-DD') INTO DATE_X
FROM XYZ;
execute immediate "I want to use DATE_X in one query"

Your code, fixed, looks like this.
Sample table first:
SQL> create table xyz as select '2022-02-26' as value from dual;
Table created.
Anonymous PL/SQL block; I'm "using" date_x to count number of rows in Scott's EMP table whose hiredate is less than date_x.
SQL> set serveroutput on
SQL> declare
2 DATE_X DATE;
3 l_cnt number;
4 begin
5 SELECT to_date(value, 'YYYY-MM-DD') INTO DATE_X FROM XYZ;
6
7 execute immediate 'select count(*) from emp where hiredate < :a'
8 into l_cnt using date_x;
9 dbms_output.put_line('Result = ' || l_cnt);
10 end;
11 /
Result = 14
PL/SQL procedure successfully completed.
SQL>

Related

executing select statement stored in table column by replacing variable value dynamically

I have simple PL/SQL block with below code
declare
rule1 varchar2(100 char);
begin
for i in (select table_name from all_tables where table_owner='EqEDI') loop
execute immediate 'select rule_stmt from rulebook ' into rule1 ;
execute immediate rule1 into result;
dbms_output.put_line('Result is '||result);
end loop;
end;
the rule statement stored in table rulebook is :
"'select count(1) from '|| tablename"
I want this above statement to be executed for all tables present for given owner
but while executing, it does not replace tablename in query with actual tables.
How can I achieve this with simple PL/SQL block.
Regards
rulebook table's contents is kind of wrong. Not that you can NOT do it the way you stored select statement into it - it is just impractical as you have to remove single quotes, remove tablename (as you can't even bind it, but concatenate what cursor returned) ... too much unnecessary jobs to be done.
Also, check all_tables and names of its columns - there's no table_owner, just owner.
Therefore, I'd suggest you to store such a statement:
SQL> SELECT * FROM rulebook;
RULE_STMT
--------------------------------------------------------------------------------
select count(*) from
Fix your PL/SQL script:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 rule1 VARCHAR2 (100 CHAR);
3 l_str VARCHAR2 (100);
4 result NUMBER;
5 BEGIN
6 FOR i IN (SELECT table_name
7 FROM all_tables
8 WHERE owner = 'SCOTT'
9 AND table_name = 'EMP')
10 LOOP
11 EXECUTE IMMEDIATE 'select rule_stmt from rulebook '
12 INTO rule1;
13
14 l_str := rule1 || i.table_name;
15
16 EXECUTE IMMEDIATE l_str
17 INTO result;
18
19 DBMS_OUTPUT.put_line ('Result is ' || result);
20 END LOOP;
21 END;
22 /
Result is 14
PL/SQL procedure successfully completed.
SQL>

Pass PL/SQL parameter as SCHEMA NAME

I'm trying to send variable schema name to cursor via procedure input
Here is my lame try, but you can see what I want to do:
CREATE OR REPLACE PROCEDURE HOUSEKEEPING
(SCHEMANAME in varchar2)
IS
CURSOR data_instances IS select table_name
from SCHEMANAME.table_name where TYPE='PERMANENT' and rownum<200 ;
BEGIN
DBMS_OUTPUT.PUT_LINE(SCHEMANAME);
END;
/
it throws expected
PL/SQL: ORA-00942: table or view does not exist
is there lawful way to make schema name work as variable? thanks
There is a way; you'll need some kind of dynamic SQL because you can't use schema (or object) names like that. For example, you could use refcursor instead.
Sample table:
SQL> create table table_name as
2 select 'EMP' table_name, 'PERMANENT' type from dual union all
3 select 'DEPT' , 'TEMPORARY' from dual union all
4 select 'BONUS' , 'PERMANENT' from dual;
Table created.
Procedure; note the way I composed SELECT statement first (so that I could display it and check whether it is correct), and then used it in OPEN. Loop is here to ... well, loop through the cursor. I'm just displaying table names I found - you'd probably do something smarter.
SQL> create or replace procedure housekeeping (par_schemaname in varchar2)
2 is
3 l_str varchar2(500);
4 l_rc sys_refcursor;
5 l_table_name varchar2(30);
6 begin
7 l_str := 'select table_name from ' ||
8 dbms_assert.schema_name(upper(par_schemaname)) ||
9 '.table_name where type = ''PERMANENT'' and rownum < 200';
10 open l_rc for l_str;
11
12 loop
13 fetch l_rc into l_table_name;
14 exit when l_rc%notfound;
15
16 dbms_output.put_line(l_table_name);
17 end loop;
18 close l_rc;
19 end;
20 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec housekeeping('SCOTT');
EMP
BONUS
PL/SQL procedure successfully completed.
SQL>

create a procedure to create a table in Pl/sql from a select statement

I have a select query
select s.site, s.date, s.loaction, s.modified, sysdate p_run_date
from table s
where s.site = 123 --p_site
and s.date >= sysdate -p_date.
i want to create a pl/sql procedure to create a table where p_date and p_site need to be input to the procedure
Why would you want to do that? We normally do NOT create tables dynamically (which is what you'd use in PL/SQL). That procedure would try to create a table with the same name every time you call it (but with different parameters) and fail because table with such a name already exists (as it was created the first time you ran the procedure). Therefore, having a one-time procedure is pretty much useless.
If it must be done, oh well ...
SQL> create or replace procedure p_test (par_deptno in number, par_job in varchar2)
2 is
3 l_str varchar2(200);
4 begin
5 l_str := 'create table my_test as ' ||
6 'select deptno, ename, job, sal ' ||
7 'from emp ' ||
8 'where deptno = ' || dbms_assert.enquote_literal(par_deptno) ||
9 ' and job = ' || dbms_assert.enquote_literal(par_job);
10 execute immediate l_str;
11 end;
12 /
Procedure created.
Testing:
SQL> exec p_test(10, 'CLERK');
PL/SQL procedure successfully completed.
SQL> select * from my_test;
DEPTNO ENAME JOB SAL
---------- ---------- --------- ----------
10 MILLER CLERK 1300
Let's try it again, with different parameters:
SQL> exec p_test(20, 'MANAGER');
BEGIN p_test(20, 'MANAGER'); END;
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
ORA-06512: at "SCOTT.P_TEST", line 10
ORA-06512: at line 1
SQL>
As I said, it'll fail. What you're trying to do is just wrong. You'd rather create a view.

Single quote at then end is missing in create view in procedure

I have a stored procedure where a string parameter need to be passed to a create a view, I am facing difficulty to enclose the string in single quotes
EXECUTE IMMEDIATE
'CREATE VIEW view_Exec_Data as
Select * from Employees
where exec_id='''' ||To_NChar(EID)||''''; --EID is input parameter and value will be 9DE4D0106D1F390EE0
Above query is generated as
EXECUTE IMMEDIATE
'CREATE VIEW view_Exec_Data as
Select * from Employees
where exec_id='9DE4D0106D1F390EE0;
Single quote at the end is missing, not sure where I am doing wrong.
We lack some info; for example, I wonder why you used TO_NCHAR ... do you really need it?
Here's an example which presumes that employees table looks like this:
SQL> create table employees (exec_id varchar2(30), name varchar2(30));
Table created.
SQL> insert into employees values ('9DE4D0106D1F390EE0', 'Littlefoot');
1 row created.
SQL> select * From employees;
EXEC_ID NAME
------------------------------ ------------------------------
9DE4D0106D1F390EE0 Littlefoot
A procedure which creates a view. I'd suggest NOT to do that. Do you really really want to have zillion views, one per each EXEC_ID someone uses as a parameter? What's the purpose of doing that? Why don't you simply
select * from employees where exec_id = :par_eid;
Anyway, here you go: in order to make that many single quotes simpler, I used q-quoting mechanism.
SQL> create or replace procedure p_crv (par_eid in employees.exec_id%type)
2 is
3 l_str varchar2(200);
4 begin
5 l_str := q'[CREATE or replace VIEW view_Exec_Data as
6 Select * from Employees
7 where exec_id= to_nchar(']' || par_eid || q'[')]';
8
9 -- when using dynamic SQL, **ALWAYS** check whether command is properly written
10 dbms_output.put_line(l_str);
11
12 -- if it looks OK, then execute it
13 execute immediate l_str;
14 end;
15 /
Procedure created.
SQL> set serveroutput on
SQL> exec p_crv('9DE4D0106D1F390EE0');
CREATE or replace VIEW view_Exec_Data as
Select * from Employees
where exec_id= to_nchar('9DE4D0106D1F390EE0')
PL/SQL procedure successfully completed.
SQL> select * From view_exec_data;
EXEC_ID NAME
------------------------------ ------------------------------
9DE4D0106D1F390EE0 Littlefoot
SQL>
If you don't need to_nchar, it gets somewhat simpler:
SQL> create or replace procedure p_crv (par_eid in employees.exec_id%type)
2 is
3 l_str varchar2(200);
4 begin
5 l_str := q'[CREATE or replace VIEW view_Exec_Data as
6 Select * from Employees
7 where exec_id= ']' || par_eid || q'[']';
8
9 -- when using dynamic SQL, **ALWAYS** check whether command is properly written
10 dbms_output.put_line(l_str);
11
12 -- if it looks OK, then execute it
13 execute immediate l_str;
14 end;
15 /
Procedure created.
SQL> exec p_crv('9DE4D0106D1F390EE0');
CREATE or replace VIEW view_Exec_Data as
Select * from Employees
where exec_id= '9DE4D0106D1F390EE0'
PL/SQL procedure successfully completed.
SQL> select * From view_exec_data;
EXEC_ID NAME
------------------------------ ------------------------------
9DE4D0106D1F390EE0 Littlefoot
SQL>
You can use:
EXECUTE IMMEDIATE
'CREATE VIEW view_Exec_Data as
Select * from Employees
where exec_id=To_NChar(''' || EID ||''')';
-- ^ 3 (') ^ 3 + 1 (')
Update
Working for me. See this:
SQL> set serverout on
SQL> declare
2 EID varchar2(100) := '9DE4D0106D1F390EE0';
3 begin
4 DBMS_OUTPUT.PUT_LINE('CREATE VIEW view_Exec_Data as
5 Select * from Employees
6 where exec_id=To_NChar(''' || EID ||''')');
7 end;
8 /
CREATE VIEW view_Exec_Data as
Select * from Employees
where
exec_id=To_NChar('9DE4D0106D1F390EE0')
PL/SQL procedure successfully completed.
SQL>

How to run a query on different schemes at once

I want to run a query on different schemes to get data and export it. I use the following code
DECLARE
sql_statment VARCHAR2(2000);
BEGIN
FOR c IN (SELECT brchcode FROM brchs) LOOP
sql_statment := 'select distinct ''' || c.brchcode ||''', t.risuid from ' || c.brchcode ||
'.reg_individualacnt_detail t
where t.historytypecode = 60';
EXECUTE IMMEDIATE sql_statment;
END LOOP;
END;
where brchcode is the name of different schemes
I can't see any output. what can I do?
Code you wrote can't work as you have to return the result into something; it is PL/SQL and requires an INTO clause. As you chose to return two values (columns) and multiple rows, that can't be a scalar variable; you could pick ref cursor or a collection, for example.
Here's an example which shows one option.
I'll be using two schemas: SCOTT (current schema) and HR. Both will be having the DEPT table.
As Scott already has it, I'll create one in HR schema and grant access to Scott (otherwise, Scott won't even see it and the procedure (i.e. the function) will fail):
SQL> connect hr/hr
Connected.
SQL> create table dept (deptno number, dname varchar2(10), loc varchar2(10));
Table created.
SQL> insert into dept values (55, 'IT', 'Zagreb');
1 row created.
SQL> grant select on dept to scott;
Grant succeeded.
SQL> commit;
Commit complete.
Back to Scott, to create a table (which contains schema names I'll be selecting from) and a function. I chose to return REF CURSOR; you could return something else, if you want.
SQL> connect scott/tiger
Connected.
SQL> create table brchs (brchcode varchar2(10));
Table created.
SQL> insert into brchs (brchcode)
2 select 'scott' from dual union all
3 select 'hr' from dual;
2 rows created.
SQL> create or replace function f_br
2 return sys_refcursor
3 is
4 l_str varchar2(4000);
5 l_rc sys_refcursor;
6 begin
7 for cur_r in (select brchcode from brchs) loop
8 l_str := l_str ||
9 'union all
10 select ' || chr(39)|| cur_r.brchcode ||chr(39) || ', d.dname
11 from ' || cur_r.brchcode ||'.dept d
12 where d.deptno > 0';
13 end loop;
14
15 l_str := ltrim(l_str, 'union all');
16
17 open l_rc for l_str;
18 return l_rc;
19 end;
20 /
Function created.
SQL>
Finally, testing:
SQL> select f_br from dual;
F_BR
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
'SCOT DNAME
----- --------------
scott ACCOUNTING
scott RESEARCH
scott SALES
scott OPERATIONS
hr IT
SQL>

Resources