PL/SQL: How to enable all triggers in the schema? - oracle

I'm trying to make a procedure that uses a cursor that enables all triggers in my schema to be enabled. However, I'm getting this Error at line 16: PL/SQL: SQL Statement ignored which is the line that I use fetch for.
CREATE OR REPLACE PROCEDURE enable_trigg_proc
IS
v_trigger_name trigger_name.user_triggers%TYPE;
CURSOR enable_trigg_cur
IS
SELECT TRIGGER_NAME INTO v_trigger_name
FROM user_triggers
WHERE STATUS = 'DISABLED';
BEGIN
OPEN enable_trigg_cur;
LOOP
FETCH enable_trigg_cur INTO v_trigger_name ;
EXIT WHEN enable_trigg_cur%NOTFOUND;
EXECUTE IMMEDIATE 'ALTER TRIGGER v_trigger_name ENABLE';
END LOOP;
close enable_trigg_cur;
END;

You don't need that much code:
SQL> begin
2 for cur_r in (select trigger_name from user_triggers) loop
3 execute immediate 'alter trigger ' || cur_r.trigger_name || ' enable';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
What's wrong with your code? INTO is required in PL/SQL's SELECT statement, but not within the cursor declaration. Also, you declared the variable in the wrong manner; should be
SQL> CREATE OR REPLACE PROCEDURE enable_trigg_proc
2 IS
3 CURSOR enable_trigg_cur
4 IS
5 SELECT TRIGGER_NAME
6 FROM user_triggers
7 WHERE STATUS = 'DISABLED';
8
9 v_trigger_name user_triggers.trigger_name%TYPE;
10 BEGIN
11 OPEN enable_trigg_cur;
12 LOOP
13 FETCH enable_trigg_cur INTO v_trigger_name ;
14 EXIT WHEN enable_trigg_cur%NOTFOUND;
15
16 EXECUTE IMMEDIATE 'ALTER TRIGGER ' || v_trigger_name || ' ENABLE';
17 END LOOP;
18 close enable_trigg_cur;
19 END;
20 /
Procedure created.
SQL> exec enable_trigg_proc;
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>

Is it possible to take a stored procedure name as input parameter in another stored procedure and execute it?

I have a set of stored procedures with the same interface and one of these stored procedures will be passed to a runner stored procedure as an input parameter. How can I execute this stored procedure within the runner proc.
I tried this by using dynamic SQL. The code snippet I wrote for this:
v_proc_query := ':1(:2, :3)';
execute immediate v_proc_query using p_proc_name, p_param1, p_param2;
But the above statement give error: ORA-00900: invalid SQL statement
I'm using Oracle 12c.
What is the right approach to achieve the goal?
Something like this, perhaps?
SQL> set serveroutput on
SQL> create or replace procedure p_test (par_deptno in number)
2 is
3 l_cnt number;
4 begin
5 select count(*)
6 into l_cnt
7 from emp
8 where deptno = par_deptno;
9 dbms_output.put_line('count = ' || l_cnt);
10 end;
11 /
Procedure created.
SQL> create or replace procedure p_test_2 (par_proc_name in varchar2, par_deptno in number)
2 is
3 l_str varchar2(200);
4 begin
5 l_str := 'begin ' ||
6 dbms_assert.sql_object_name(par_proc_name) ||
7 '(' || par_deptno || ');' ||
8 'end;';
9 execute immediate l_str;
10 end;
11 /
Procedure created.
SQL> exec p_test_2('p_test', 10);
count = 3
PL/SQL procedure successfully completed.
SQL>

Execute Immediate?

Why do we use execute immediate command in PL/SQL?
I'm looking at some procedures written by a previous colleague, and I see that the person has used execute immediate a lot many time to log the progress of the procedure and also when truncating the tables.
My question is why would he do so? Can we not just truncate tables just like that in pl/sql proc?
Oracle wouldn't allow execution of DDL inside executable block. This is not allowed
begin
alter table . . .
end;
Originally Oracle had SYS.DBMS_DDL package to do this job. But it was cumbersome to use, so oracle introduced execute immediate circa v9.
Apart from executing DDL from PL/SQL (which you've already been told), execute immediate is used to run dynamic SQL. What would that be? Creating statements that depend on information that is not known at the time you're creating the PL/SQL procedure. For example, selecting from several tables in your schema:
SQL> set serveroutput on
SQL> declare
2 l_str varchar2(1000);
3 l_cnt number;
4 begin
5 for cur_r in (select table_name from user_tables
6 where table_name in ('EMP', 'DEPT', 'BONUS')
7 )
8 loop
9 l_str := 'select count(*) from ' || cur_r.table_name;
10 execute immediate l_str into l_cnt;
11 dbms_output.put_line(cur_r.table_name ||': '|| l_cnt);
12 end loop;
13 end;
14 /
BONUS: 0
DEPT: 4
EMP: 14
PL/SQL procedure successfully completed.
SQL>
Similarly, you might create a function that uses table (or column) names dynamically, e.g.
SQL> create or replace function f_cnt (par_table_name in varchar2)
2 return number
3 is
4 l_str varchar2(1000);
5 l_cnt number;
6 begin
7 l_str := 'select count(*) from ' || dbms_assert.sql_object_name(par_table_name);
8 execute immediate l_str into l_cnt;
9 return l_cnt;
10 end;
11 /
Function created.
SQL> select f_cnt('emp') from dual;
F_CNT('EMP')
------------
14
SQL>

Single cursor for two different SQL in Oracle

I have a scenario where i want to use a cursor for two different sql.
create or replace procedure(p_load_type in number)
as
create cursor prod_cur
is
/* This is the 1st SQL*/
select product_id,
product_name
from Test_product;
prod_rec prod_cur%rowtype;
/* here is the second sql that i want cursor open for this when p_load_type=2
select product_id,
product_name
from Test_product tp,
Test_delta_cases tdc
where tp.product_id=tdc.product_id;*/
begin
if p_load_type=1 then /* opening for 1st sql*/
open prod_cur
elsif p_load_type=2 then /* opening for 2nd sql*/
open prod_cur
end if;
loop
some logic............
end loop;
end;
Please use formatting to format your code in your question. Anyway, you can do with REF CURSORS, eg
SQL> create or replace
2 procedure P(p_type int ) is
3 rc sys_refcursor;
4
5 cursor c_template is select 1 x, 1 y from dual;
6 l_rows c_template%rowtype;
7
8 begin
9 if p_type = 1 then
10 open rc for select empno, deptno from scott.emp;
11 else
12 open rc for select empno, sal from scott.emp;
13 end if;
14
15 loop
16 fetch rc into l_rows;
17 exit when rc%notfound;
18 dbms_output.put_line(l_rows.x||','||l_rows.y);
19 end loop;
20 end;
21 /
Procedure created.
SQL> set serverout on
SQL> exec p(1);
7369,20
7499,30
7521,30
7566,20
7654,30
7698,30
7782,10
7788,20
7839,10
7844,30
7876,20
7900,30
7902,20
7934,10
PL/SQL procedure successfully completed.
SQL> exec p(2);
7369,800
7499,1600
7521,1250
7566,2975
7654,1250
7698,2850
7782,2450
7788,3000
7839,5000
7844,1500
7876,1100
7900,950
7902,3000
7934,1300
PL/SQL procedure successfully completed.

How to run multiple statements in one sqlscript for Oracle

I'm trying to run a few statements in one sql file but it does not work.
declare
new_sequence INTEGER;
begin
select LAST_NUMBER + 1
into new_sequence
from user_sequences
where SEQUENCE_NAME = 'MLTS_SEQUENCE';
execute immediate 'Create sequence Table_SEQ start with '
|| new_sequence ||' increment by 1';
end;
If i run this block with the option 'execute as one statement' in the eclipse database plugin it works.
How can i mark the sqlscript to run each of these blocks as one statement, to execute the script later with sqlplus or something different than eclipse?
I tried GO in front and / at the end but that also didn't work.
As long as it's on its own line and left aligned, it should be ok in sql*plus:
SQL> create sequence MLTS_SEQUENCE start with 1 cache 20;
Sequence created.
SQL> select MLTS_SEQUENCE.nextval from dual;
NEXTVAL
----------
1
SQL> declare
2 new_sequence INTEGER;
3 begin
4 select LAST_NUMBER + 1
5 into new_sequence
6 from user_sequences
7 where SEQUENCE_NAME = 'MLTS_SEQUENCE';
8
9 execute immediate 'Create sequence Table_SEQ start with '
10 || new_sequence ||' increment by 1';
11 end;
12 /
PL/SQL procedure successfully completed.
SQL> select Table_SEQ.nextval from dual;
NEXTVAL
----------
22
The proper format for sqlplus is the following:
declare
...
begin
...
end;
/

Resources