Creating Oracle SQL Trigger Error - sql

This is what I need to accomplish: Create a TRIGGER named tgr_customer_insert that will fire AFTER a row is inserted into the customers table.
The trigger can be created after you create the cardholder table, so it can be in the same ps16a.sql file just created. This trigger will insert a row into the cardholder table when a row is inserted into the temp_table_customers table. Here are the columns to insert:
card_number (this is inserted using the seq_cardholder sequence number)
customer_id (this is a bind variable from the temp_table_customer table using the :new.column_name syntax)
credit_limit (this is a bind variable from the temp_table_customer table using the :new.column_name syntax)
This is my code:
`CREATE OR REPLACE TRIGGER tgr_customer_insert
AFTER INSERT
ON customers
FOR EACH ROW
BEGIN
-- Insert record into customers table
INSERT INTO cardholder
( card_number,
customer_id,
credit_limit
)
VALUES
( new.seq_cardholder,
:new.customer_id,
:new.credit_limit
);
END;
`
Error is: ORA-24344: success with compilation error
Line 3 Position 4.
Hair is being torn out. Thank you in advance for you time with this matter.

I think you are missing a ':' in INSERT VALUES for first value binding.
CREATE OR REPLACE TRIGGER tgr_customer_insert
AFTER INSERT
ON customers
FOR EACH ROW
BEGIN
-- Insert record into customers table
INSERT INTO cardholder
( card_number,
customer_id,
credit_limit
)
VALUES
( :new.seq_cardholder,
:new.customer_id,
:new.credit_limit
);
END;
If, "seq_cardholder" is a sequence then you have to use as below:
CREATE OR REPLACE TRIGGER tgr_customer_insert
AFTER INSERT
ON customers
FOR EACH ROW
BEGIN
-- Insert record into customers table
INSERT INTO cardholder
( card_number,
customer_id,
credit_limit
)
VALUES
( seq_cardholder.nextval,
:new.customer_id,
:new.credit_limit
);
END;

Related

SQL Server: If a row is inserted in one table, how do I write a trigger to insert that same row in a different table?

I'm not sure how to create this trigger,.I need to add a row in pub_info table when a row is inserted in publishers table. The exact same row. SQL server
CREATE TRIGGER checkCity
ON pub_info
AFTER INSERT
AS
IF -- a row is inserted into publishers table,
-- how do I add the same row into pub_info table?
INSERT VALUES(#pub_id, NULL, 'new publishers')
BEGIN
END;
You have to create a trigger on publishers table and not on pub_info .
The inserted data is available in the INSERTED table in the trigger
CREATE TRIGGER checkCity
ON publishers
AFTER INSERT
AS
BEGIN
INSERT INTO pub_info(pubid, pubname, pub_description)
SELECT pubid, pubname, pub_description
FROM INSERTED;
END;

Mutating trigger in Oracle

I create the following tables:
create table lessons(
id number,
name_teacher varchar2(9),
name_student varchar2(40),
start_lesson date,
end_lesson date
);
I inserted the following datas:
insert into lessons values (001,'Peter','Thomas',to_date('2015-12-15','YYYY-MM-DD'),to_date('2015-12-22','YYYY-MM-DD'));
insert into lessons values (002,'Eli','Alice',to_date('2015-06-16','YYYY-MM-DD'),to_date('2015-06-23','YYYY-MM-DD'));
insert into lessons values (003,'Daniel','Thomas',to_date('2015-08-15','YYYY-MM-DD'),to_date('2015-08-20','YYYY-MM-DD'));
Data that you cant add by the trigger.
insert into lessons values (001,'Peter','Alice',to_date('2015-12-16','YYYY-MM-DD'),to_date('2015-12-25','YYYY-MM-DD'));
insert into lessons values (002,'Eli','Thomas',to_date('2015-06-13','YYYY-MM-DD'),to_date('2015-06-20','YYYY-MM-DD'));
The question is how to make a trigger that does not allow me to add students who have teachers who overlap in time, like "Peter" or "Eli".
--- My problem ---
Oracle returns me an error of mutants tables.
you neen an after insert / update Trigger that fire after the comlete insert or update and not after earch row:
create or replace trigger check_intersections_trg
on
lessons
after insert or update
declare
v_res NUMBER;
begin
select count(*)
into v_res
from lessons l1
join lessons l2 on l1.name_student = l2.name_student
and l1.start_lesson <= l2.end_lesson
and l2.start_lesson <= l1.end_lesson
;
if v_res > 0 than
raise_application_error( -20999, 'intersection found');
end if;
end;
/

SQL - How to create a trigger for two joined tables which is used for inserting

Ok , so I know that inserting information in a view based on two joined tables is impossible.
In order to do so , I need to create a trigger to insert the information in both tables , when an insert is made in that view.
For example :
CREATE VIEW myJoinedView AS
SELECT name,g.value from students
JOIN grades g on g.id=students.id;
The trigger is not working :
CREATE TRIGGER myTrigger
INSTEAD OF INSERT ON myJoinedView
BEGIN
INSERT INTO students
(name,value)
SELECT i.myJoinedView
FROM inserted i
INNER JOIN grades
ON i.id = grades.id
END myTrigger;
Then I'm trying to insert :
INSERT INTO myJoinedView VALUES ('Alex',10);
I don't know if the syntax is correct , I did not find any helpful documentation on this specific type of trigger.
I'm getting this error:
Error(10,46): 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
<< continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall merge
pipe purge
Any help will be well received.
Thank you!
You need to either perform the inserts separately with separate single table insert or merge statements or by using a multi table insert (insert all) statement. Assuming you have a sequence to generate the id you are joining on for example this code will work in a very rudimentary way, but has some significant issues:
create table students ( id number primary key
, name varchar2(60));
create table grades( id number not null
, value number
, constraint grades_fk1 foreign key (id) references students(id));
create sequence student_id_seq;
create or replace view studentgrades as
select name, value from students s join grades g on s.id = g.id;
create or replace trigger studentgrades_ii_trg
instead of insert on studentgrades
begin
insert all into students(id, name) values (student_id_seq.nextval, name)
into grades(id, value) values (student_id_seq.nextval, value)
select :new.name name, :new.value value from dual;
end;
/
insert into studentgrades values ('Alex',10);
insert into studentgrades values ('Alex',8);
The BIG issue with the above trigger is that every time a grade is inserted for 'Alex' a new student record for 'Alex' is also created instead of reusing the previous student record for 'Alex'. That's probably not the desired behavior. Instead it should probably just insert a new grade record for Alex. One way to acheive this is for the studentgrades view to include the id column from the students table so you can uniquely identify which student to add the grade to, updating the trigger as needed:
create or replace view studentgrades as
select s.id, name, value from students s join grades g on s.id = g.id;
create or replace trigger studentgrades_ii_trg
instead of insert on studentgrades
declare
newid students.id%type;
begin
if :new.id is null then
newid := student_id_seq.nextval;
else
newid := :new.id;
end if;
insert all when :new.id is null
then into students(id, name) values (id, name)
else into grades(id, value) values (id, value)
select newid id, :new.name name, :new.value value from dual;
end;
/
insert into studentgrades values (null, 'Paul',10);
insert into studentgrades values (student_id_seq.currval, 'Paul',8);
However, now what happens if you try this:
insert into studentgrades values (student_id_seq.currval, 'Mary',10);
In this case the name is effectively ignored and Paul gets a new grade so again this isn't quite right. The question is should Paul's name be updated to Mary, or should a new student record for Mary be created, or should an exception be raised?

How can I modify this trigger to include column-name, old-value and new-value?

Suppose, a trigger that keeps track of AREA-table and records the changes in AREA_LOGGING_TABLE.
CREATE TABLE AREA
( AREA_NUMBER NUMBER,
AREA_NAME VARCHAR(20)
)
CREATE TABLE AREA_LOGGING_TABLE
( WHO_MODIFIED VARCHAR(20),
WHEN_MODIFIED DATE,
OLD_VALUE BLOB,
NEW_VALUE BLOB,
COLUMN_NAME VARCHAR(30)
)
I want to record username, date-time, column-name, old-data, and, new-data.
How can I do that?
CREATE OR REPLACE TRIGGER AREA_MODIFY_LOGGER_COLUMN_LVL
AFTER INSERT or UPDATE or DELETE
ON AREA
REFERENCING OLD AS old_data NEW AS new_data
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing the DELETE on the table
SELECT user INTO v_username
FROM dual;
-- Insert record into audit table
INSERT INTO AREA_LOGGING_TABLE(who_modified, when_modified, old_value, new_value)
VALUES ( v_username, sysdate, :old_data.area_number, :new_data.area_number);
END;
This is not working.
Besides, I don't know how to include column-name here.
The utl_raw.cast_to_raw function can be used to convert your values to BLOB.
Regarding the column_name, I think you can hard code it in the insert statement as you already doing it after :NEW and :OLD.
The nvl function was used to handle nulls in :NEW \ :OLD.
CREATE OR REPLACE TRIGGER AREA_MODIFY_LOGGER_COLUMN_LVL
AFTER INSERT or UPDATE or DELETE
ON AREA
REFERENCING OLD AS Old NEW AS New
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
-- Find username of person performing the DELETE on the table
SELECT user INTO v_username
FROM dual;
if nvl(:old.area_number, -1) <> nvl(:new.area_number, -1) then
-- Insert record into audit table
INSERT INTO AREA_LOGGING_TABLE(who_modified, when_modified, old_value, new_value, column_name)
VALUES ( v_username, sysdate, utl_raw.cast_to_raw(:Old.area_number), utl_raw.cast_to_raw(:New.area_number), 'AREA_NUMBER');
end if;
if nvl(:old.area_name , '-1') <> nvl(:new.area_name, '-1') then
-- Insert record into audit table
INSERT INTO AREA_LOGGING_TABLE(who_modified, when_modified, old_value, new_value, column_name)
VALUES ( v_username, sysdate, utl_raw.cast_to_raw(:Old.AREA_NAME), utl_raw.cast_to_raw(:New.AREA_NAME), 'AREA_NAME');
end if;
END;
Just to giving you brief for trigger to enhance your concept for trigger
You have below inbuilt table created by SQL when trigger fired.
- deleted (i.e. select #empid=d.Emp_ID from deleted d)
- inserted (i.e. select #empid=i.Emp_ID from inserted i) (can be used in Insert/update operation)

how to create trigger on derived table?

I have created two tables customer and orders and I have already inserted some data in customer table but nothing is in orders table. Now I want to create a trigger on orders table that would copy only the id column ( which is defined in customer table as primary key) in orders table of o_id ( which is defined as foreign key in orders table ).
I want to check my created trigger and fix it if you find any error in it.
My trigger for orders table :
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
BEGIN
SELECT ID
INTO :NEW.o_id
FROM customer;
END;
Thanks.
I want to create a trigger on orders table that would copy only the
id column
you can start doing like this , (by the way I didnt understand where you want to use your derived table ? what is the query)
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
declare cnt number (3);
BEGIN
select count(1) into cnt from customer where id=:new.id; // its is checking
if cnt=0 then
insert into customer (id) values (:new.id);
end if;
// you can add raise error here
END;
/
you want to copy a value from customer table to orders table with help of trigger so firstly you will be needing to create the trigger on customertable not on orderstable ,since for every insert done in the customer table the trigger will be fired once which will insert a value in orders table.
CREATE OR REPLACE TRIGGER tri_order
AFTER INSERT
ON customer
FOR EACH ROW
BEGIN
INSERT INTO orders
(o_id)
SELECT :NEW.ID
FROM customer;
END;
You must specify a rule for finding the customer.
For example:
CREATE OR REPLACE TRIGGER tri_order
BEFORE INSERT
ON orders
FOR EACH ROW
BEGIN
SELECT c.ID
INTO :NEW.o_id
FROM customer c
WHERE c.customer_code = :NEW.customer_code;
END;