I want to execute the RAISE error based on the SELECT statement.
I am sure that will work or not. If possible can someone help with the below code
DECLARE
A ExcEPTION;
V_T VARCHAR2(1000);
BEGIN
SELECT ' RAISE A ' INTO V_T FROM DUAL;
EXECUTE IMMEDIATE V_T;
EXCEPTION
WHEN A THEN
DBMS_OUTPUT.PUT_LINE('ABC');
END ;
It'll work, but not as you wanted (I guess). You'll have to dynamically execute the whole PL/SQL block that contains exception declaration and its handling section. Something like this:
SQL> declare
2 v_t varchar2(1000);
3 begin
4 select ' RAISE A ' into v_t from dual;
5 execute immediate
6 'declare a exception; begin ' || v_t ||
7 '; exception when a then dbms_output.put_line(''abc''); end;';
8 end ;
9 /
abc
PL/SQL procedure successfully completed.
SQL>
Related
Is there any way to assign a select query to local variable in PL/SQL other than select into statement?. Because select into throwing null value exception if the select query returns null value. Thanks
It would be helpful to post your code, but here is an example that should show the behavior you need. Assume there is a table called courses_tbl:
declare
cnumber number := NULL;
CURSOR c1
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = 'XYZ';
BEGIN
open c1;
fetch c1 into cnumber;
if c1%notfound then
-- Do something here if you care about not found.
cnumber := 999; -- whatever
end if;
you can read about cursor attributes here
Seems that you need to use the exception handling as follows:
... -- Your procedure other code
BEGIN
SELECT <COLUMN_NAME> INTO <YOUR_VARIABLE>
FROM .....
WHERE ....
EXCEPTION WHEN NO DATA FOUND THEN
<YOUR_VARIABLE> := NULL;
END;
... -- Your procedure other code
You can use EXECUTE IMMEDIATE...INTO...:
DECLARE
nCnumber NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 1'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #1 : nCnumber = ' || nCnumber);
nCnumber := NULL;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 100'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #2 : nCnumber = ' || nCnumber);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('SELECT #2 : NO DATA FOUND');
END;
END;
db<>fiddle here
You've seen how to do it using a cursor or exception handling section (which is - in my opinion - the right way to do it). However, as we're discussing, here's yet another option - an aggregate function. It won't return NO_DATA_FOUND but NULL.
This is what you have now:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select job
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
This is what you might do:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select max(job)
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>
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>
I'm trying to make a procedure which gives grants to users on a certain type of objects
Here's what I did
CREATE OR REPLACE PROCEDURE grants AS
DECLARE
Cursor c IS select OBJECT_NAME as view_name from all_objects where object_type in ('VIEW');
BEGIN
FOR tmp in c
LOOP
EXECUTE IMMEDIATE 'GRANT ALL on ' || tmp.view_name || ' TO my_users';
END LOOP;
END;
But I'm getting an 'end-of-file' symbole encountered [...]' error...
Do you guys have an idea to make this procedure work ?
Remove DECLARE:
SQL> CREATE OR REPLACE PROCEDURE grants AS
2 CURSOR c IS
3 SELECT OBJECT_NAME AS view_name
4 FROM all_objects
5 WHERE object_type IN ('VIEW');
6 BEGIN
7 FOR tmp IN c
8 LOOP
9 EXECUTE IMMEDIATE 'GRANT ALL on ' || tmp.view_name || ' TO my_users';
10 END LOOP;
11 END;
12 /
Procedure created.
I am trying to make dynamic sql like this 'select col1,col2 from '|| my_table ||' it works fine but I want to write like this sql_stmt:='select col1,col2 from :myTable'; execute immediate sql_stmt using my_table; but I have error I have same error when I want to do something like this tooo v_filter := my_proc(); sql_stmt:='select col1,col2 from my_table where :filter' execute immediate sql_stmt using v_filter; is it impossible to build dynamic sql like this with using ? If it is impossible what is another way to avoid sql injections ?
When you want to use table names in dynamic SQL, yes - you'll have to concatenate them. In order to avoid SQL injection, use DBMS_ASSERT.SQL_OBJECT_NAME.
Here's an example:
SQL> create or replace procedure p_test (par_table in varchar2) is
2 l_table varchar2(30);
3 l_str varchar2(200);
4 l_cnt number;
5 begin
6 l_table := dbms_assert.sql_object_name(par_table);
7
8 l_str := 'select count(*) from ' || par_table;
9 execute immediate (l_str) into l_cnt;
10 dbms_output.put_line('Table contains ' || l_cnt || ' rows');
11 end;
12 /
Procedure created.
SQL>
SQL> exec p_test('dept');
Table contains 4 rows
PL/SQL procedure successfully completed.
SQL> exec p_test('delete from emp');
BEGIN p_test('delete from emp'); END;
*
ERROR at line 1:
ORA-44002: invalid object name
ORA-06512: at "SYS.DBMS_ASSERT", line 316
ORA-06512: at "SCOTT.P_TEST", line 6
ORA-06512: at line 1
SQL>
[EDIT: WHERE clause]
This works:
SQL> create or replace procedure p_test (par_table in varchar2,
2 par_filter in varchar2) is
3 l_table varchar2(30);
4 l_str varchar2(200);
5 l_cnt number;
6 begin
7 l_table := dbms_assert.sql_object_name(par_table);
8
9 l_str := 'select count(*) from ' || par_table ||
10 ' where deptno = :filter';
11 execute immediate (l_str) into l_cnt using par_filter;
12 dbms_output.put_line('Table contains ' || l_cnt || ' rows');
13 end;
14 /
Procedure created.
SQL> exec p_test('emp', '10');
Table contains 3 rows
PL/SQL procedure successfully completed.
SQL>
WHERE clause, modified so that it contains only the WHERE keyword, while the rest is to be used as a parameter:
SQL> create or replace procedure p_test (par_table in varchar2,
2 par_filter in varchar2) is
3 l_table varchar2(30);
4 l_str varchar2(200);
5 l_cnt number;
6 begin
7 l_table := dbms_assert.sql_object_name(par_table);
8
9 l_str := 'select count(*) from ' || par_table ||
10 ' where :filter';
11 execute immediate (l_str) into l_cnt using par_filter;
12 dbms_output.put_line('Table contains ' || l_cnt || ' rows');
13 end;
14 /
Procedure created.
SQL> exec p_test('emp', 'deptno = 10');
BEGIN p_test('emp', 'deptno = 10'); END;
*
ERROR at line 1:
ORA-00920: invalid relational operator
ORA-06512: at "SCOTT.P_TEST", line 11
ORA-06512: at line 1
SQL>
It won't work; is that what you're asking?
Some more reading about dynamic SQL on Oracle, as well as here, on Stack overflow (How can I create a dynamic WHERE clause.
I have sp in oracle. My SP is shown below
create or replace
PROCEDURE GETMONITORING
(
v_namabarang in varchar2 default null,
v_JenisLayanan in varchar2 default null,
cv_1 IN OUT SYS_REFCURSOR
)
AS
v_where VARCHAR2(200);
v_Select VARCHAR2(200);
v_from VARCHAR2(200);
v_final VARCHAR2(200);
v_result VARCHAR2(200);
BEGIN
v_Select:='select * ';
v_from :='from permohonan ';
v_where :='where sysdate=sysdate ';
IF nvl(length(v_namabarang),0) <> 0 then
v_Where := v_Where || ' AND namabarang like ''' || v_namabarang|| '%'' ';
end if;
IF nvl(length(v_jenislayanan),0) <> 0 then
v_Where := v_Where || ' AND jenislayanan like ''' || v_jenislayanan || '%'' ';
end if;
v_final :=v_select|| v_from|| v_where;
dbms_output.put_line(v_result);
END;
I tried to exec in sqlplus by
SQL> var r refcursor;
SQL> exec getmonitoring('AC','1',:r);
SQL>print :r;
and the result is "ORA-24338": Statement handle not executed
So, how I exec my SP in sqlplus ? Thanks
The error is evident from the fact that you never OPEN the CURSOR but making a reference to the SYS_REFCURSOR as OUT parameter.
ORA-24338: statement handle not executed
Cause: A fetch or describe was attempted before executing a statement handle.
Action: Execute a
statement and then fetch or describe the data.
You need to use OPEN cursor FOR... statement:
v_final :=v_select|| v_from|| v_where;
-- open the cursor
OPEN cv_1 FOR v_final;
On a side note, while compiling PL/SQL in SQL*Plus, if you see errors, you should always use SHOW ERRORS to see the full error stack.
For example,
SQL> create or replace procedure p
2 as
3 begin
4 null
5 end;
6 /
Warning: Procedure created with compilation errors.
SQL> show errors
Errors for PROCEDURE P:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PLS-00103: Encountered the symbol "END" when expecting one of the
following:
;
The symbol ";" was substituted for "END" to continue.
So, now you know the exact line number and the error message which will help you to debug and fix the error.