How to create a Trigger in oracle? - sql

I have oracle database 11gR2 and i want to create some triggers automatically with a block .
when i want to run query in below , i have an error .
My block is :
declare
tablesid number ;
tablenames varchar2(4000);
cursor c1 is
select id , title from hr.tables;
begin
open c1;
loop
fetch c1 into tablesid , tablenames;
CREATE OR REPLACE TRIGGER tablenames||'_before_insert'
before insert
on hr.tablenames
DECLARE
columnid number ;
columnval number ;
columntitle varchar(4000);
cursor c2 is
select id from hr.columns where tableid = tablesid ;
BEGIN
-- open c2 ;
for rec in c2 loop
select title into columntitle from hr.columns where id = rec.id
insert into hr.rowaction(columnid,newvalue,oldvalue,actiondate)
(
select id ,:new.columntitle,:old.columntitle,sysdate
from hr.tabletiltes
where id = rec.id
)
select title into columntitle from hr.columns where id = rec.id;
dbms_output.put_line(columntitle);
end loop;
end;
end loop ;close c1; end;
ORA-06550: line 11, column 6:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
( begin case declare end exit for goto if loop mod null
pragma raise return select update while with
<<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action :
Bind Variable "new" is NOT DECLARED
anonymous block completed
Bind Variable "new" is NOT DECLARED
anonymous block completed
Thanks

A trigger is a standalone separate piece of code that is usually considered DDL, the language that defines metadata for objects.
You cannot have a trigger declaration embedded inside a PL/SQL block. IF you need to CREATE some PL/SQL code on the fly - not a great idea - consider the DMBS_DDL.CREATE_WRAPPED procedure. You seem to have EXECUTE IMMEDIATE in mind as well. If so, have a read on this: (http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_ddl.htm)
You should define your trigger BEFORE running your PL/SQL in other words. Make two scripts.

Related

IBM plsql - cursor

I am new with PLSQL (IDM db2) and I am trying to create a procedure to find and delete some admin_tasks if they exist.
Explanation:
By running the bellow query1, I can find out the list of tasks in the scheduler:
SELECT * FROM SYSTOOLS.ADMIN_TASK_LIST;
To delete the task, I can run this query2:
call sysproc.admin_task_remove('TASK_NAME', null);
So I want to create a procedure to delete all tasks with the pattern "My_Task_*".
This should delete all the tasks with that pattern and leave the other existent tasks intact. The procedure should handle cases where the admin_tasks doesn't exist, or no admin_tasks were ever created, and should run without throwing any errors.
I have researched and found out that this can be made using cursors.
Can you help me to implement this?
EDIT:
I managed to find this solution:
BEGIN
FOR v1 AS c1 CURSOR FOR
SELECT NAME
FROM SYSTOOLS.ADMIN_TASK_LIST
WHERE NAME LIKE 'My\_task\_%' ESCAPE '\'
DO
call sysproc.admin_task_remove(NAME, null);
END FOR;
END
This seems to work except if the SYSTOOLS.ADMIN_TASK_LIST was not yet defined.
If it's not defined than I get this error when I run the query: If it is not defined I get this error
: [Code: -204, SQL State: 42704]
"SYSTOOLS.ADMIN_TASK_LIST" is an undefined name.. SQLCODE=-204,
SQLSTATE=42704, DRIVER=4.25.1301
So how can I bypass this error? DOing something like first checking if SYSTOOLS.ADMIN_TASK_LIST is defined, if its defined to the above query if not do nothing.
Presuming that your client tool uses '#' as a statement delimiter.
BEGIN
FOR L1 AS
SELECT NAME
FROM SYSTOOLS.ADMIN_TASK_LIST
WHERE NAME LIKE 'My\_task\_%' ESCAPE '\'
DO
CALL ADMIN_TASK_REMOVE (L1.NAME, NULL);
END FOR;
END
Update:
With error handling for non-existing table. The error handler just "eats" the error on non-existing table use.
You must use dynamic sql for that.
BEGIN
DECLARE SQLSTATE CHAR (5);
DECLARE L_NAME VARCHAR (128);
DECLARE C1 CURSOR FOR S1;
DECLARE EXIT HANDLER FOR SQLSTATE '42704' BEGIN END;
PREPARE S1 FROM
'
SELECT NAME
FROM SYSTOOLS.ADMIN_TASK_LIST
WHERE NAME LIKE ''My\_task\_%'' ESCAPE ''\''
';
OPEN C1;
L1:
LOOP
FETCH C1 INTO L_NAME;
IF SQLSTATE = '02000' THEN LEAVE L1; END IF;
CALL ADMIN_TASK_REMOVE (L_NAME, NULL);
END LOOP L1;
CLOSE C1;
END

how to select into an array in pl/sql?

I'm trying to add some ids into an array:
CREATE OR REPLACE TYPE array_of_numbers AS VARRAY(10)OF NUMBER(10);
declare
student_ids array_of_numbers;
begin
select nrleg BULK COLLECT into student_ids from student where nrleg = 123458;
FOR i IN 1..student_ids.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(student_ids(i));
END LOOP;
end;
but I get the following errors:
--------- -------------------------------------------------------------
3/1 PLS-00103: Encountered the symbol "DECLARE"
10/4 PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge json_exists json_value json_query json_object json_array
Errors: check compiler log
Could someone explain what I did wrong?
Some DDL needs to be terminated with a /; a type can have a PL/SQL body so this is one of them. To run that all at once as a script do:
CREATE OR REPLACE TYPE array_of_numbers AS VARRAY(10)OF NUMBER(10);
/
declare
student_ids array_of_numbers;
begin
select nrleg BULK COLLECT into student_ids from student where nrleg = 123458;
FOR i IN 1..student_ids.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(student_ids(i));
END LOOP;
end;
/
You don't need the semicolon on the end of the CREATE here, but it doesn't hurt; but for some other commands (including other DDL like create table) having both would cause it to try to execute the statement twice, which could cause an error.
SQL Developer won't complain about the lack of a / after the last PL/SQL block in a script, but other tools will, so it's better to always include that one too.
db<>fiddle
Incidentally, another way to see the contents of the array in SQL Developer is with a ref cursor:
var rc refcursor
declare
student_ids array_of_numbers;
begin
select nrleg BULK COLLECT into student_ids from student where nrleg = 123458;
open :rc for select * from table(student_ids);
end;
/
print rc
... but then you might as well just select directly from the table, without any PL/SQL.

PL/SQL procedure not compiling

I have a PL/SQL procedure that is not compiling. The errors are:
Error(3,7): PLS-00103: Encountered the symbol "INTO" when expecting one of the following: ( begin case declare exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "INTO" was ignored.
Error(8,1): PLS-00428: an INTO clause is expected in this SELECT statement.
My code:
CREATE OR REPLACE PROCEDURE findvisitsandlaborcosts
as
begin
select * from SI.customer;
end;
/
I have googled an online syntax checker and it says on the first line there is an error. But WHERE?!? It seems to be correct. I have googled the syntax of declaring a procedure and I have cross-checked many times. It must be something simple that I am overlooking...
in a PLSQL code, you need a placeholder to keep results of a SELECT query. Since PLSQL engine is expecting INTO clause within SELECT statement.
To begin with, you can select a set of columns and assign their values to local variables.
Your code should be like this -
CREATE OR REPLACE PROCEDURE findvisitsandlaborcosts
as
v_column1 SI.customer.column1%type;
v_column2 SI.customer.column2%type;
begin
select column1, column2 into v_column1, v_column2 from SI.customer;
end;
/
Note - you need to replace column1 and column2 with actual column names before running this code at your end.
If you want the results to get displayed on the caller of the procedure, then you would define an out parameter and print the records outside of the procedure
CREATE OR REPLACE PROCEDURE findvisitsandlaborcosts(x out sys_refcursor)
as
begin
open x for
select * from dual;
end;
/
--Note this block of code needs to be run in sqlci or sqldeveloper
define m ref cursor;
exec findvisitsandlaborcosts(:x);
print x;
Oracle 12c has support for implict return results
Have a look at this link
https://oracle-base.com/articles/12c/implicit-statement-results-12cr1

cant compile any cursor example

I'm trying to make any cursor example working, but just cant make it happen.
IDE: Oracle SQL developer
database: 10g sql oracle
I've tried this three examples, but it didn't compile well. Can someone provide me with working examples?
First one:
EDIT: works! just had 'where where'
DECLARE
CURSOR person_data_cur
as
SELECT *
FROM personal_data
WHERE where name='Karol';
BEGIN
FOR person_data
IN person_data_cur
LOOP
DBMS_OUTPUT.put_line (
person_data.surname);
END LOOP;
END;
and this:
DECLARE my_cursor1 CURSOR FOR
SELECT name, surname
FROM personal_data
WHERE name='Karol';
^error:
Error report -
ORA-06550: row 1, column 27:
PLS-00103: found symbol "FOR" when expected one of following:
:= . ( # % ; not null range default character
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
or even this:
EDIT: this one is OK, just my IDE ignored first two lines, and executed others... but i guess it was OK since it wasnt inside any block or procedure
CURSOR c1
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = name_in;
For Second Example : Your syntax is incorrect.
The pseudo code for the cursor is :
Declare
Cursor Cursor_name
is
select * from table where <Conditions>;
Begin
For cur_Rec in cursor_name
Loop
<what you want to do>
End Loop;
End;
For the third example, I believe name_in is an input parameter, please correct the syntax to :
CURSOR c1 (name_in VARCHAR2)
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = name_in;
Please refer Cursor Declaration for more details

Oracle SQL Stored Procedure Cursor print

Ok so I am working on a homework assignment using stored procedures.
Essentially i am just trying to use a stored procedure to run a query then print the results.
Here is what i have so far.
create or replace procedure movie_actors (mtitle varchars)as
DECLARE
CURSOR c1 is SELECT "NAME",GENDER,ADDRESS FROM MOVIESTAR WHERE "NAME" in(
SELECT STARNAME FROM STARSIN WHERE MOVIETITLE=mtitle);
actor_name MOVIESTAR.NAME%TYPE;
actor_gender MOVIESTAR.NAME%TYPE;
actor_address MOVIESTAR.ADDRESS%TYPE;
BEGIN
LOOP
FETCH c1 INTO actor_name;
FETCH c1 INTO actor_gender;
FETCH c1 INTO actor_address;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(mtitle ||', '||actor_name||': '||actor_gender||', '||actor_address);
END LOOP;
END;
I am new to databases and stored procedures. I am not sure if i am really going about this the best way.
It should be pretty simple, I am not sure what I am doing wrong.
This is the compiler error i am getting.
Error(2,1): PLS-00103: Encountered the symbol "DECLARE" when expecting one of the
following: begin function pragma procedure subtype type <an identifier> <a
double-quoted delimited-identifier> current cursor delete exists prior external
language The symbol "begin" was substituted for "DECLARE" to continue.
Error(16,4): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the
following: ( begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with <an identifier> <a double-quoted
delimited-identifier> <a bind variable> << continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall merge pipe purge
Any help would be greatly appreciated.
First, you have an invalid type:
create or replace procedure movie_actors (mtitle varchars)as
^
This should be varchar2, not varchars.
Second, you don't need the DECLARE here. The "as" kinda substitutes for it. Start your proc like this:
create or replace procedure movie_actors (mtitle varchar2)as
CURSOR c1
Finally, I strongly recommend changing this:
CURSOR c1 is SELECT "NAME",GENDER,ADDRESS FROM MOVIESTAR WHERE "NAME"
... to this (no double quotes):
CURSOR c1 is SELECT NAME,GENDER,ADDRESS FROM MOVIESTAR WHERE NAME
The double quotes will make the column name case sensitive. You're lucky in this case because the default in Oracle is uppercase, but sooner or later using double quotes like this will cause you trouble - there are plenty of StackOverflow postings from frustrated users who've lost hours or time from using double quotes when they didn't have to.