Trigger to check foreign key not working in PLSQL - sql

Here are my 2 tables that I am using
create table EMPLOYEE (
Eid number(5) primary key,
Ename char(30),
Designation char(30));
create table Attendance (
Eid number(5) references EMPLOYEE(Eid),
tdate date,
attendance char(2) check(attendance in('P','A')));
Here is the Procedure I am using to take attendance
create or replace PROCEDURE take_attendance(
id IN number,
attendance IN char) IS
begin
insert into ATTENDANCE Values(id, sysdate, attendance);
end;
Here is the Trigger I am using
create or replace TRIGGER to_take_attendance
before insert or update of eid on ATTENDANCE
for each row
declare
CURSOR c(n number) is select * from EMPLOYEE where eid = :new.eid;
e c%rowtype;
invalid_id EXCEPTION;
begin
open c(:new.eid);
fetch c into e;
if c%NOTFOUND then
raise invalid_id;
else
NULL;
end if;
EXCEPTION
when invalid_id then
close c;
raise_application_error(-20001,'Invalid ID');
close c;
end;
Here are the Errors I am getting
begin
*
ERROR at line 1:
ORA-20001: Invalid ID
ORA-06512: at "101503028.TO_TAKE_ATTENDANCE", line 17
ORA-04088: error during execution of trigger '101503028.TO_TAKE_ATTENDANCE'
ORA-06512: at "101503028.TAKE_ATTENDANCE", line 5
ORA-06512: at line 2
I am not sure why I am getting those errors. I am new to PL/SQL is my question my be very stupid.
Thanks!
EDIT - Removed the others in exception.

You are getting errors because your trigger works as expected.
You are trying to insert to ATTENDANCE, ID that does not exist in EMPLOYEE.
Exception defined in your code:
raise_application_error(-20001,'Invalid ID');
Error received:
ORA-20001: Invalid ID

Related

Oracle drop table if exists is throwing an error starting at line 1: in command

We are trying to drop all tables in a database and then create them again, but oracle is throwing an error. the error report is:
Error report -
ORA-06550: line 12, column 1:
PLS-00103: Encountered the symbol "CREATE"
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
and the code is:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || EMPLOYEE;
EXECUTE IMMEDIATE 'DROP TABLE ' || ADDRESS;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
CREATE TABLE EMPLOYEE(
EmployeeID int,
FirstName varchar(225),
LastName varchar(255),
Position varchar(255),
SSN int,
Address varchar(255),
Phone int,
AddressID int,
PRIMARY KEY (EmployeeID),
FOREIGN KEY (AddressID) REFERENCES ADDRESS(AddressID)
);
CREATE TABLE ADDRESS(
AddressID int,
Street varchar(225),
City varchar(225),
State varchar(225),
Zip int
);
We want to do this for all tables but so far it's not working for the two tables we are trying to drop at the start.
Should've been like this:
SQL> BEGIN
2 BEGIN
3 EXECUTE IMMEDIATE 'DROP TABLE EMPLOYEE';
4 EXCEPTION
5 WHEN OTHERS THEN
6 IF sqlcode != -942 THEN
7 RAISE;
8 END IF;
9 END;
10
11 BEGIN
12 EXECUTE IMMEDIATE 'DROP TABLE ADDRESS';
13 EXCEPTION
14 WHEN OTHERS THEN
15 IF sqlcode != -942 THEN
16 RAISE;
17 END IF;
18 END;
19
20 END;
21 /
PL/SQL procedure successfully completed.
SQL> CREATE TABLE ADDRESS(
2 AddressID int primary key,
3 Street varchar(225),
4 City varchar(225),
5 State varchar(225),
6 Zip int
7 );
Table created.
SQL> CREATE TABLE EMPLOYEE(
2 EmployeeID int,
3 FirstName varchar(225),
4 LastName varchar(255),
5 Position varchar(255),
6 SSN int,
7 Address varchar(255),
8 Phone int,
9 AddressID int,
10 PRIMARY KEY (EmployeeID),
11 FOREIGN KEY (AddressID) REFERENCES ADDRESS(AddressID)
12 );
Table created.
SQL>
What did you do wrong?
table names should be enclosed into single quotes with dynamic SQL because - if they don't exist, code will fail
enclose each dynamic SQL statement into its own BEGIN-EXCEPTION-END block to avoid problems when one of tables exists (and another does not)
terminate PL/SQL block with a slash (line #11); otherwise, some tools (like SQL*Plus) won't be able to execute whole code as a script
first create ADDRESS table (and add a primary key constraint because foreign key on EMPLOYEE will fail otherwise)
Try to swap the CREATE tables, because you try to use a FOREIGN KEY (AddressID), which is at the moment of creation not accessable.
CREATE TABLE ADDRESS(
...
CREATE TABLE EMPLOYEE(
...

ORA-01403: no data found from INSERT trigger

I'm trying to configure a database using oracle 11g release 2 where I created a table named UTILITY:
create table utility
(
u_id varchar2(12),
name varchar2(20)NOT NULL,
status varchar2(10),
paid_amount number(7,2)NOT NULL,
month varchar2 (2) NOT NULL,
year varchar2 (4) NOT NULL,
company varchar2(20)NOT NULL,
constraint u_id_pk primary key(u_id)
);
I also created a sequence
CREATE SEQUENCE "ASMADB"."UTILITY_ID_SEQ" MINVALUE 1 MAXVALUE 9999999999
INCREMENT BY 1 START WITH 1 CACHE 10 NOORDER NOCYCLE ;
and a trigger for the table:
create or replace trigger uility_id
before insert on utility
for each row
begin
select to_char('U')||'-'||lpad(utility_id_seq.nextval,9,'0')
into :new.u_id
from utility;
end;
but whenever I try to insert values in utility following error occurs:
Error starting at line : 1 in command
insert into utility values (' ','Electricity Bill','due',5340.59,to_char(to_date('12/06/2020','dd/mm/yyyy'),'mm'),to_char(to_date('12/06/2020','dd/mm/yyyy'),'yyyy'),'Rakib Electricity')
Error report
ORA-01403: no data found
ORA-06512: at "ASMADB.UILITY_ID", line 2
ORA-04088: error during execution of trigger 'ASMADB.UILITY_ID'
It will be very helpful if someone helps me to resolve this error.
Note: the table Utility is empty.
Not like that; simply
create or replace trigger uility_id
before insert on utility
for each row
begin
:new.u_id := 'U-' || lpad(utility_id_seq.nextval,9,'0');
end;

Making a trigger to not create an insurance policy for a driver that has been involved in an accident

Hello I am brand new to triggers in SQL and need some help with one. I am working with 3 tables involving drivers, car accidents, and insurance policy. What I am trying to do is create a trigger that will not allow insurance policies to be able to be made for drivers involved in an accident.
Here is what I have tried so far:
CREATE TABLE insurance_policy(
id INT,
ssn_driver INT,
expiration_date DATE,
PRIMARY KEY (id)
);
CREATE TABLE accident(
id INT,
ssn_driver INT,
accident_date DATE,
details VARCHAR2(64),
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES insurance_policy,
FOREIGN KEY (ssn_driver) REFERENCES driver
);
CREATE TABLE driver(
ssn_driver INT,
name VARCHAR2(64),
age INT CHECK (age>15),
PRIMARY KEY(ssn_driver)
);
CREATE TRIGGER no_insurance_policy
AFTER INSERT OR UPDATE ON insurance_policy
FOR EACH ROW
BEGIN
IF EXISTS (select ssn_driver FROM Inserted INNER JOIN accident)
BEGIN
rollback transaction
raiserror ('some message', 16, 1)
END
END
This doesn't compile, but I'm just confused on how to proceed from here. Can anyone help me out with creating this trigger?
EDIT: Here is the error
Error starting at line : 31 in command -
BEGIN
IF EXISTS (select ssn_driver FROM Inserted INNER JOIN accident)
BEGIN
rollback transaction
raiserror ('some message', 16, 1)
END
END
Error report -
ORA-06550: line 2, column 58:
PLS-00103: Encountered the symbol "JOIN" when expecting one of the following:
) , with group having intersect minus start union where
connect
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
First, you need to do BEFORE not AFTER insert. Then, your syntax is not even Oracle. Here is approximately what you need to do. I have not tested it.
CREATE TRIGGER no_insurance_policy
BEFORE INSERT OR UPDATE ON insurance_policy
FOR EACH ROW
DECLARE
v_accidentCout NUMBER(10);
BEGIN
Select Count(*) Into v_accidentCout
From accident
Where ssn_driver = old.ssn_driver;
If v_accidentCout > 0 Then
raise_application_error(-12345, 'Driver has accidents');
End If;
END;
/
I would leave commit/rollback to the block that calls insert/update.

trigger to override the message to error(ORA-02292)

I want override the message that generate error (ORA-02292).
It is message like that
ORA-02292: integrity constraint (IVANKA.FK_SUPPLIER) violated - child record found
I want a trigger to override the above message to his example on this (MY override :))
I tried do like that
for first create table
CREATE TABLE supplier
( supplier_id numeric(10) not null,
supplier_name varchar2(50) not null,
contact_name varchar2(50),
CONSTRAINT supplier_pk PRIMARY KEY (supplier_id)
);
CREATE TABLE products
( product_id numeric(10) not null,
supplier_id numeric(10) not null,
CONSTRAINT fk_supplier
FOREIGN KEY (supplier_id)
REFERENCES supplier (supplier_id)
);
then insert data
INSERT INTO supplier
(supplier_id, supplier_name, contact_name)
VALUES (1000, 'Microsoft', 'Bill Gates');
INSERT INTO products
(product_id, supplier_id)
VALUES (50000, 1000);
then do trigger
create or replace trigger sup_z
after delete on supplier
for each row
declare
v_error_constraint exception;
pragma exception_init(v_error_constraint, -2292);
begin
null;
exception
When v_error_constraint then
raise_application_error(-20001,
'My ovvervide:)');
End;
then do delete to generate message
DELETE from supplier
WHERE supplier_id = 1000
but I see not my message in trigger I see
ORA-02292: integrity constraint (IVANKA.FK_SUPPLIER) violated - child record found
Can you help me? What am I doing wrong?
Your trigger is fired after the DELETE has been done, so it will never fire if the DELETE gives an error.
You could use a BEFORE trigger to avoid the DELETE, if you find some child records; for example:
create or replace trigger sup_z
before delete on supplier
for each row
declare
vNumberOfChild number;
begin
select count(1)
into vNumberOfChild
from products
where supplier_id = :old.supplier_id;
--
if vNumberOfChild > 0 then
raise_application_error(-20001, 'My ovveride:)');
end if;
End;
Another way could be defining a procedure to handle the delete:
SQL> create or replace procedure deleteSupplier(p_id in numeric) is
2 vNumberOfChild number;
3 begin
4 select count(1)
5 into vNumberOfChild
6 from products
7 where supplier_id = p_id;
8 --
9 if vNumberOfChild > 0 then
10 dbms_output.put_line('My ovveride');
11 else
12 delete supplier
13 where supplier_id = p_id;
14 end if;
15 end;
16 /
Procedure created.
SQL> set serveroutput on
SQL> exec deleteSupplier(1000);
My ovveride
PL/SQL procedure successfully completed.
This avoids running the delete checking the data before, so you need no triggers.
Check this out (Display custom message when constraint is violated PL/SQL). I think you want something similar.
When all you need is just the message to be printed, why do we need a trigger in the first place? Shouldn't we be handling this just with an exception alone?
declare
v_error_constraint exception;
pragma exception_init(v_error_constraint, -2292);
begin
DELETE from supplier
WHERE supplier_id = 1000;
exception
When v_error_constraint then
raise_application_error(-20001,
'My ovvervide:)');
End;

After insert trigger update

CREATE TABLE "EMPLOYEE_BP"
( "EMP_ID" VARCHAR2(10) NOT NULL ENABLE,
"FNAME" VARCHAR2(20),
"LNAME" VARCHAR2(20),
"JOB_ROLE" VARCHAR2(20),
"AIRPORT_CODE" VARCHAR2(10) NOT NULL ENABLE,
"SALARY" NUMBER(9,0),
"MOBILE" NUMBER(10,0)
);
CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, : NEW.AIRPORT_CODE, : NEW.SALARY, : NEW.MOBILE);
DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
END;
--> Apparently constraints are not inserted into backup tables
​The table gets created, but it gives me an error for the trigger on line 4,where the begin statement is. Ther error is error at line 4 statement ignored. The synthax seems ok and I'm confident it's a small error but I can't figure it out. I am using Oracle.
Thanks in advance.
Running the trigger as you have it, I actually get an internal Oracle error, which is not good. But I think the problem is with the spaces you have between the : and the NEW.
This works for me:
SQL> CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
2 FOR EACH ROW
3 DECLARE
4 BEGIN
5 INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, :NEW.AIRPORT_CODE, :NEW.SALARY, :NEW.MOBILE);
6 DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
7 END;
8 /
Trigger created.
I'm not an Oracle expert but you would either need to strike your DECLARE line or actually declare something based on this example
CREATE or REPLACE TRIGGER emp_after_insert AFTER INSERT ON EMPLOYEE
FOR EACH ROW
DECLARE
unused varchar2(10);
BEGIN
INSERT INTO EMPLOYEE_BP values (:NEW.EMP_ID, :NEW.FNAME, :NEW.LNAME, :NEW.JOB_ROLE, :NEW.AIRPORT_CODE, :NEW.SALARY, :NEW.MOBILE);
DBMS_OUTPUT.PUT_LINE('Record successfully inserted into emp_backup table');
END;