How to prevent entering value in table when primary is used on other table? - sql

I have to construct and populate a supertype-subtype relationship, but I cannot get it to work the way it is supposed to be. Basically PERSON table is the supertype of table STUDENT and TEACHER(subtypes). But a person can be either a student or a teacher.
Attributes:
PERSON(p_id, name, dob)
STUDENT (s_id, p_id, grade)
TEACHER(t_id, p_id, tel)
Both student and teacher should have names and DOB's along with the p_id as a foreign key, but if it exist on one table it shouldn't be on the other
CREATE TABLE PERSON ( -- SUPERTYPE
p_id NUMBER(2) CONSTRAINT c1 PRIMARY KEY,
name CHAR(15),
dob DATE
);
CREATE TABLE STUDENT ( -- SUBTYPE
s_id NUMBER(2) CONSTRAINT c2 PRIMARY KEY,
p_id_fk,
grade CHAR(1),
FOREIGN KEY (p_id_fk) REFERENCING PERSON (p_id)
);
CREATE TABLE TEACHER( -- SUBTYPE
t_id NUMBER(4) CONSTRAINT c3 PRIMARY KEY,
p_id_fk,
tel CHAR(8),
FOREIGN KEY (p_id_fk) REFERENCING PERSON (p_id)
);
INSERT INTO PERSON VALUES (11, 'John', to_date('12/12/12', 'dd/mm/yy'));
INSERT INTO PERSON VALUES (22, 'Maria', to_date('01/01/01', 'dd/mm/yy'));
INSERT INTO PERSON VALUES (33, 'Philip', to_date('02/02/02', 'dd/mm/yy'));
INSERT INTO STUDENT VALUES (98, 11, 'A');
INSERT INTO TEACHER VALUES (1234, 11, 14809510);
How to prevent Person 11 (John) from existing in both tables?

One option is to use database triggers, one for each table (STUDENT and TEACHER); they look the same:
Trigger on STUDENT:
SQL> create or replace trigger trg_bi_stu
2 before insert on student
3 for each row
4 declare
5 l_cnt number;
6 begin
7 -- inserting into STUDENT: check whether that person exists in TEACHER table
8 select count(*)
9 into l_cnt
10 from teacher
11 where p_id_fk = :new.p_id_fk;
12
13 if l_cnt > 0 then
14 raise_application_error(-20001, 'That person is a teacher; can not be a student');
15 end if;
16 end;
17 /
Trigger created.
Trigger on TEACHER:
SQL> create or replace trigger trg_bi_tea
2 before insert on teacher
3 for each row
4 declare
5 l_cnt number;
6 begin
7 -- inserting into TEACHER: check whether that person exists in STUDENT table
8 select count(*)
9 into l_cnt
10 from student
11 where p_id_fk = :new.p_id_fk;
12
13 if l_cnt > 0 then
14 raise_application_error(-20001, 'That person is a student; can not be a teacher');
15 end if;
16 end;
17 /
Trigger created.
SQL>
Testing:
SQL> INSERT INTO STUDENT VALUES (98, 11, 'A');
1 row created.
SQL>
SQL> INSERT INTO TEACHER VALUES (1234, 11, 14809510);
INSERT INTO TEACHER VALUES (1234, 11, 14809510)
*
ERROR at line 1:
ORA-20001: That person is a student; can not be a teacher
ORA-06512: at "SCOTT.TRG_BI_TEA", line 11
ORA-04088: error during execution of trigger 'SCOTT.TRG_BI_TEA'
SQL>

Use a materialized view with an appropriate constraint to check complex requirements such as this.
For example, let's create the tables and a materialized view, add data to the tables, and refresh the MV:
CREATE TABLE PERSON ( -- SUPERTYPE
p_id NUMBER(2) CONSTRAINT c1 PRIMARY KEY,
name CHAR(15),
dob DATE
);
CREATE TABLE STUDENT ( -- SUBTYPE
s_id NUMBER(2) CONSTRAINT c2 PRIMARY KEY,
p_id_fk,
grade CHAR(1),
FOREIGN KEY (p_id_fk) REFERENCING PERSON (p_id)
);
CREATE TABLE TEACHER( -- SUBTYPE
t_id NUMBER(4) CONSTRAINT c3 PRIMARY KEY,
p_id_fk,
tel CHAR(8),
FOREIGN KEY (p_id_fk) REFERENCING PERSON (p_id)
);
CREATE MATERIALIZED VIEW PERSON_MV
REFRESH COMPLETE
AS SELECT p.P_ID,
s.S_ID,
t.T_ID
FROM PERSON p
LEFT OUTER JOIN STUDENT s
ON s.P_ID_FK = p.P_ID
LEFT OUTER JOIN TEACHER t
ON t.P_ID_FK = p.P_ID;
-- Add constraint to the table underlying the MV
ALTER MATERIALIZED VIEW PERSON_MV
ADD CONSTRAINT PERSON_MV_CK1
CHECK( (S_ID IS NULL AND -- either both are NULL
T_ID IS NULL) OR
( (S_ID IS NULL OR -- or only one is NULL
T_ID IS NULL) AND
(S_ID IS NOT NULL OR
T_ID IS NOT NULL)));
INSERT ALL
INTO PERSON (P_ID, NAME, DOB) VALUES (11, 'John', to_date('12/12/2012', 'dd/mm/yyyy'))
INTO PERSON (P_ID, NAME, DOB) VALUES (22, 'Maria', to_date('01/01/2001', 'dd/mm/yyyy'))
INTO PERSON (P_ID, NAME, DOB) VALUES (33, 'Philip', to_date('02/02/2002', 'dd/mm/yyyy'))
SELECT * FROM DUAL;
COMMIT;
INSERT INTO STUDENT VALUES (98, 11, 'A');
COMMIT;
BEGIN
DBMS_MVIEW.REFRESH('PERSON_MV', 'C', '', TRUE, FALSE, 0, 0, 0, FALSE, FALSE);
END;
/
SELECT *
FROM PERSON_MV;
Note the constraint added to the materialized view:
ALTER MATERIALIZED VIEW PERSON_MV
ADD CONSTRAINT PERSON_MV_CK1
CHECK( (S_ID IS NULL AND -- either both are NULL
T_ID IS NULL) OR
( (S_ID IS NULL OR -- or only one is NULL
T_ID IS NULL) AND
(S_ID IS NOT NULL OR
T_ID IS NOT NULL)));
This constraint allows data to exist where:
a PERSON row exists, but neither a related STUDENT or TEACHER row exists
a PERSON row exists along with either a related STUDENT or TEACHER row, but not both
So when we execute the final SELECT from the materialized view we get:
P_ID S_ID T_ID
11 98 -
33 - -
22 - -
Now let's modify the script above, adding the following just after the INSERT INTO STUDENT:
INSERT INTO TEACHER VALUES (1234, 11, 14809510);
COMMIT;
If we re-run the entire script, we find that when DBMS_MVIEW.REFRESH is called to refresh the materialized view we get:
ORA-12008: error in materialized view or zonemap refresh path ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 3012
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 2424
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 88
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 253
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 2405
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 2968
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 3255
ORA-06512: at "SYS.DBMS_SNAPSHOT_KKXRCA", line 3287
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 16
ORA-06512: at line 2
ORA-06512: at "SYS.DBMS_SQL", line 1721
This is Oracle's rather long-winded way to say that the constraint was violated.
See this LiveSQL Oracle session

Following on from #Bob's materialized view approach, a version that catches the issue on commit might look like this:
CREATE MATERIALIZED VIEW LOG ON STUDENT WITH PRIMARY KEY, ROWID;
CREATE MATERIALIZED VIEW LOG ON TEACHER WITH PRIMARY KEY, ROWID;
CREATE MATERIALIZED VIEW PERSON_HACK (p_id_fk, marker, rid)
BUILD IMMEDIATE
REFRESH ON COMMIT AS
SELECT p_id_fk, 1, ROWID FROM STUDENT
UNION ALL
SELECT p_id_fk, 2, ROWID FROM TEACHER;
ALTER MATERIALIZED VIEW PERSON_HACK
ADD CONSTRAINT PERSON_HACK_PK PRIMARY KEY (p_id_fk);
That should act similarly to a deferred constraint, erroring when the MV is refreshed (and its primary key violated) on commit. With concurrent inserts the second session to commit would see the error.
Live SQL, though it seems to have some issues with MVs (reported elsewhere). It should report the constraint violation, not throw ORA-12008. But I don't currently have access to test elsewhere - neither SQL Fiddle or db<>fiddle allow MVs to be created.
Of course, if you haven't been taught about MVs yet then using one in an assignment might look a bit odd. It seems a bit more likely that you've been taught about objects and the assignment is expecting those - even though they are very rarely used in the real world (within the DB), they seem to be taught anyway, along with old join syntax and other bad practices...

There exists four ways how to map an inheritance to relational database.
You are using the most exotic third option, which is causing the problem. Consider to switch to one of the other options as a solution.
The first three are well understood and documented, this page provides usefull links.
Basically you can map
1) all classes in one table
2) use one table for all concrete classes
3) define one table for aech class
All this options have some problems either with excesive joins or with deactivated constraints (e.g. you can't define non nullable columns in option 1), so for completness the option 4) is do not use inheritance in relational database.
You have tried to implement the option 3), but the problem is that all tables must inherite the same primary key (to enfornce 1:1 relation) and use this primary key as a foreign key.
Here the overview of all options for your example
-- 1) single table
CREATE TABLE PERSON (
p_id NUMBER(2) CONSTRAINT pers_pk PRIMARY KEY,
name CHAR(15),
dob DATE,
grade CHAR(1),
tel CHAR(8),
person_type VARCHAR2(10) CONSTRAINT pers_type CHECK (person_type in ('STUDENT','TEACHER'))
);
-- 2) table per concrete class
CREATE TABLE STUDENT (
p_id NUMBER(2) CONSTRAINT stud_pk PRIMARY KEY,
name CHAR(15),
dob DATE,
grade CHAR(1)
);
CREATE TABLE TEACHER(
p_id NUMBER(2) CONSTRAINT tech_pk PRIMARY KEY,
name CHAR(15),
dob DATE,
tel CHAR(8)
);
-- 3) table per class
CREATE TABLE PERSON (
p_id NUMBER(2) CONSTRAINT pers_pk PRIMARY KEY,
name CHAR(15),
dob DATE
);
CREATE TABLE STUDENT (
p_id NUMBER(2) CONSTRAINT stud_pk PRIMARY KEY,
grade CHAR(1),
FOREIGN KEY (p_id) REFERENCING PERSON (p_id)
);
CREATE TABLE TEACHER(
p_id NUMBER(2) CONSTRAINT tech_pk PRIMARY KEY,
tel CHAR(8),
FOREIGN KEY (p_id) REFERENCING PERSON (p_id)
);
INSERT INTO PERSON (P_ID, NAME, DOB) VALUES (11, 'John', to_date('12/12/2012', 'dd/mm/yyyy'));
INSERT INTO PERSON (P_ID, NAME, DOB) VALUES (22, 'Maria', to_date('01/01/2001', 'dd/mm/yyyy'));
INSERT INTO PERSON (P_ID, NAME, DOB) VALUES (33, 'Philip', to_date('02/02/2002', 'dd/mm/yyyy'));
INSERT INTO STUDENT (P_ID, GRADE) VALUES (11, 'A');
INSERT INTO TEACHER (P_ID, TEL) VALUES (11, 14809510);

Related

Why am I getting this error when I want the the employee to NOT be below 18 and above 60?

the previous error was fixed. A group member was inserting the Salary amount into 0 precision-specified numbers.
Basically, I want to give an error when the age of an employee is less than 18 or more than 60
please suggest how I can do it.
Trigger statement
create or replace TRIGGER check_birth_date
BEFORE INSERT OR UPDATE ON employee
FOR EACH ROW
BEGIN
IF( months_between(sysdate,:new.DateOfBirth)/12 < 18 or
months_between(sysdate,:new.DateOfBirth)/12 > 60 )
THEN
RAISE_APPLICATION_ERROR(
-20001,
'EMPLOYEE MUST BE ABOVE 18 AND BELOW 60' );
END IF;
END;
The insert statement I am trying to insert
INSERT INTO EMPLOYEE VALUES(1002, 'DAVID', '21/apr/2011', 'M', '21/jun/2010', 28000.00, 'HR', 'HR MANAGER', 77845322, 'C');
The errors
- ORA-06512
- ORA-04088
- ORA-20001
CREATE TABLE STATEMENT
CREATE TABLE EMPLOYEE(
EmployeeID NUMBER(4),
Name VARCHAR2(20),
Hiredate DATE NOT NULL,
Gender VARCHAR(1),
DateOfBirth DATE NOT NULL,
Salary NUMBER(8,2),
DName VARCHAR(20),
PName VARCHAR(20),
Phone NUMBER(8) NOT NULL,
GLETTER VARCHAR(1),
CONSTRAINT EMPLOYEE_EMPLOYEEID_PK PRIMARY KEY(EMPLOYEEID),
CONSTRAINT EMPLOYEE_DNAME_FK FOREIGN KEY(DNAME) REFERENCES DEPARTMENT(DNAME),
CONSTRAINT EMPLOYEE_PNAME_FK FOREIGN KEY(PNAME) REFERENCES POSITION(PNAME),
CONSTRAINT EMPLOYEE_GLETTER_FK FOREIGN KEY(GLETTER) REFERENCES GRADE(GLETTER),
CONSTRAINT GENDER_CK CHECK (GENDER='M' or GENDER='F')
);
Your code is right, if you check your input data and run it by yourself you can see it. I run it and the result is:
You trigger is working fine. I have created employee table without any foreign key constraints (since no reference table is available to me) and the trigger is working as it should be.
It's denying entry of any record with age than 18 and more than 60 but it's allowing any record within age 18 to 60.
Please try to insert below line:
INSERT INTO EMPLOYEE VALUES(1002, 'DAVID', '21/apr/2000', 'M', '21/jun/2000', 28000.00, 'HR', 'HR MANAGER', 77845322, 'C');

Triggers working correctly, but raise application error causing some errors with insert statements

I have my code shown below. Everything is working correctly but when my insert statements violate the trigger it throws errors because of my raise_application_error.
--Drop tables in case they were created previously
DROP TABLE enrollment Purge;
DROP TABLE offering Purge;
DROP TABLE faculty Purge;
DROP TABLE course Purge;
DROP TABLE student Purge;
--Create student table
CREATE TABLE student(StdID number(3) constraint student_StdID_PK primary key,
StdFN varchar2(10),
StdLN varchar2(15),
StdCity varchar2(15),
StdState char(2),
StdZip number(5),
StdMajor varchar2(4),
StdClass char(2),
StdGPA number(2,1),
StdBalance NUMBER (12,2));
--create a table for courses and their descriptions
CREATE TABLE course(CourseNo varchar2(8) constraint course_courseNo_PK primary key,
CrsDesc varchar2(40),
CrsCredits number(1));
--create faculty table
CREATE TABLE Faculty(FacID number(4) constraint faculty_FacID_PK primary key,
FacFN varchar2(10),
FacLN varchar2(15),
FacDept varchar2(4),
FacRank varchar2(4),
FacHireDate date,
FacSalary number(6),
FacSupervisor number(4));
--create table for offered courses
CREATE TABLE Offering(OfferNo number(4) constraint offering_OfferNo_PK primary key,
CourseNo varchar(8)constraint offering_crs_no references course(courseno),
OffTerm varchar2(6),
OffYear number(4),
OffLoca varchar(6),
OffTime varchar(8),
OffDay varchar(5),
FacSSN number(4)constraint offering_fac_FK references faculty(facID));
--create table for student enrollment
CREATE TABLE enrollment(StdID number(3),
OfferNo number(4),
EnrGrade char(2),
constraint enrollment_PK primary key (StdID,OfferNo),
constraint enrollment_std_ID foreign key(StdID) references student(stdID),
constraint enrollment_class_ID foreign key(offerno) references offering(offerno));
CREATE OR REPLACE TRIGGER UNPAID_BALANCE
BEFORE INSERT ON STUDENT
FOR EACH ROW
DECLARE
BAL NUMBER;
BEGIN
BAL := :NEW.STDBALANCE;
IF BAL > 500
THEN
RAISE_APPLICATION_ERROR(-20001, 'Your balance is too high to register. Please pay to continue.');
END IF;
END;
/
CREATE OR REPLACE TRIGGER ENROLL_MAX
BEFORE INSERT ON ENROLLMENT
FOR EACH ROW
DECLARE
NOFSTUDENTS BINARY_INTEGER;
BEGIN
SELECT COUNT(*) INTO NOFSTUDENTS
FROM ENROLLMENT
WHERE OFFERNO = :NEW.OFFERNO AND ENRGRADE IS NULL;
DBMS_OUTPUT.PUT_LINE(NOFSTUDENTS);
IF (NOFSTUDENTS + 1) > 2
THEN
RAISE_APPLICATION_ERROR(-20003, 'EXCEED MAX NO OF STUDENTS ALLOWED');
END IF;
END;
/
--populate student table
INSERT INTO student values(101,'Joe','Smith','Eau Clare','WI',18121,'IS','FR',3.8,225.25);
INSERT INTO student values(102, 'Rob','King', 'Melrose', 'MN', 56352, 'IS','JR',3.2,120.98);
INSERT INTO student values(103, 'Dan','Robinson', 'Sartell', 'MN', 98042, 'IS','JR',3.6, 36);
INSERT INTO student values(104,'Sue','Williams','St.Cloud','MN',56301,'ACCT','SR',3.2,2386.55);
INSERT INTO student values(105,'Don','Robinson','St.Paul','MN',55103,'MKTG','SR',3.4, 306);
--populate course table
INSERT INTO Course values('CSCI 200','Elements of Computing',3);
INSERT INTO Course values('IS 250','Application of Program Dev. I',3);
INSERT INTO Course values('IS 251','Application of Program Dev. II',3);
INSERT INTO Course values('IS 454', 'Data Mining for Decision Support',3);
INSERT INTO Course values('IS 356','Systems Analysis and Design I',3);
INSERT INTO Course values('IS 460', 'Project Management',3);
INSERT INTO Course Values('ACCT 291','Accounting Principles II',3);
INSERT INTO Course values('IS 443','Database Design',3);
--populate faculty table
INSERT INTO faculty values(9001,'Leonard','Vince','IS','ASST','12-Apr-1997',67000,9003);
INSERT INTO faculty values(9002,'Victor','Strong','CSCI','ASSO','8-Aug-1999',70000,9003);
INSERT INTO faculty values(9003,'Nicki','Colan','IS','PROF','20-Aug-1981',75000,9010);
INSERT INTO faculty values(9004,'Fred','Wells','ACCT','ASST','28-Aug-1996',60000,9010);
INSERT INTO faculty values(9010,'Chris','Macon','ACCT','ASST','4-Aug-1980',75000,Null);
--populate offering table
INSERT INTO offering values(2201,'CSCI 200','Spring',2017,'ECC135','10:30AM','MWF',9002);
INSERT INTO offering values(2202,'CSCI 200','Spring',2017,'ECC135','8:00AM','MWF',9002);
INSERT INTO offering values(1102,'ACCT 291','Spring',2017,'CH 14A','2:00AM','MWF',9004);
INSERT INTO offering values(2203,'IS 356','Fall',2017,'CH494','3:30AM','TTH',9001);
INSERT INTO offering values(2204,'IS 251','Fall',2017,'CH494','12:30AM','TTH',9003);
INSERT INTO offering values(1101,'ACCT 291','Fall',2017,'CH350','12:30AM','TTH',9010);
INSERT INTO offering values(2205,'IS 443','Fall',2017,'CH494','9:30AM','MWF',9003);
--populate enrollment table
INSERT INTO enrollment values(101,2201,'A');
INSERT INTO enrollment values(102,2202,'B');
INSERT INTO enrollment values(102,2203,null);
INSERT INTO enrollment values(103,2203,null);
INSERT INTO enrollment values(103,2201,'C');
INSERT INTO enrollment values(103,1101,null);
INSERT INTO enrollment values(104,2202,'A');
INSERT INTO enrollment values(101,2203,null);
INSERT INTO enrollment values(101,1101,null);
INSERT INTO enrollment values(101,2205,null);
INSERT INTO enrollment values(102,2205,null);
INSERT INTO enrollment values(104,2205,null);
Is there a way I can make this look cleaner/better in the script output section because one specific case is this error message that pops up because of the raise application error.
Error starting at line : 129 in command -
INSERT INTO enrollment values(104,2202,'A')
Error report -
ORA-02291: integrity constraint (ADMIN_BF.ENROLLMENT_STD_ID) violated - parent key not found
The error that you are facing is clear enough. There is not student 104 in the table, so you cannot create a dependent record in enrollment. This error is not related to your triggers, but to your data.
Now let's look at the insert statement for that particular user:
INSERT INTO student values(104,'Sue','Williams','St.Cloud','MN',56301,'ACCT','SR',3.2,2386.55);
You are attempting to input a balance of 2386.55. But your trigger UNPAID_BALANCE prevents balances that are above 500, so that insert raises application error "Your balance is too high to register", which is the root cause of the problem. You need to fix that insert.
Side note: there is another problem lurking in the last series of inserts into enrollments. Trigger ENROLL_MAX allows only two students per OFFERNO, but you are attempting to assign three students to offer 2203, and three as well to offer 2205. This will raise application error "EXCEED MAX NO OF STUDENTS ALLOWED".

Oracle if value to be inserted in foreign key is -1, insert null instead

I have a xml script I'm reading from to populate my database with data. One of the nodes in the xml file don't have a idDirector field (the nodes are movies) and so the xml reads a -1 as idDirector and then my stored procedure tries to insert -1 into the fk field and this makes my database returna constraint error : director -1 doesn't exist in Director table. How can I make it so it inserts null instead and make my fk field nullable?
CREATE TABLE Film (
PRIMARY KEY (idFilm),
FOREIGN KEY (idDirector) REFERENCES Director
);
Thank you
Looks like CASE to me, e.g.
insert into film (id_film, id_director)
select id_film,
case when id_director = -1 then null
else id_director
end
from ...
Will it work? Yes:
SQL> create table director (id number primary key);
Table created.
SQL> create table film (id number primary key, id_director number references director);
Table created.
SQL> insert into director values (100);
1 row created.
Inserting -1 fails:
SQL> insert into film (id, id_director) values (1, -1);
insert into film (id, id_director) values (1, -1)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.SYS_C0065885) violated - parent key not
found
Inserting NULL works:
SQL> insert into film (id, id_director) values (1, null);
1 row created.
SQL>

SQL Integrity constraint-Parent key not found

I have looked over the internet and their solutions wont fix my problem, hence I'm asking for help here to check if there's mistakes in my coding.
I wanted to create a temporary table populated by other source tables and then implement it into the fact table. I have checked if the data type and the parameter is matching or the sequence of the keys but still it's giving me the error
"ORA-02291: integrity constraint (SYSTEM.SYS_C007167) violated -
parent key not found"
Fact Table:
CREATE TABLE DW_ITEMS7364 (
DW_ID int not null,
ManID char(5),
WHID char(5),
STKID char(5),
Profit number,
CONSTRAINT DW_ID PRIMARY KEY (DW_ID),
FOREIGN KEY(ManID) REFERENCES DW_MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES DW_WAREHOUSE7364,
FOREIGN KEY(StkID) REFERENCES DW_STOCKITEM7364);
CREATE SEQUENCE seq_items7364 START WITH 101 increment by 1;
CREATE TRIGGER trg_items7364 BEFORE INSERT OR UPDATE ON DW_ITEMS7364
FOR EACH ROW
BEGIN
SELECT seq_items7364.NEXTVAL
INTO :new.DW_ID
FROM dual;
END;
Temporary Table:
CREATE TABLE TEMP_TAB7364 AS( SELECT m.ManID, w.WHID, s.STKID, (s.SellingPrice-s.PurchasePrice) AS "Profit"
FROM MANUFACTURER7364 m LEFT OUTER JOIN STOCKITEM7364 s ON s.ManID = m.ManID
RIGHT OUTER JOIN WAREHOUSE7364 w on s.WHID = w.WHID WHERE s.SELLINGPRICE IS NOT NULL AND s.PURCHASEPRICE IS NOT NULL
);
These are my source tables:
CREATE TABLE MANUFACTURER7364(
ManID char(5),
ManName varchar (25),
CityID char(5) NOT NULL,
PRIMARY KEY(ManID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE WAREHOUSE7364(
WHID char(5),
MaxNoOfPallets number,
CostPerPallet number,
SecurityLevel char(1),
FreezerFacilities varchar(10),
QuarantineFacilities varchar(10),
CityID char(5) NOT NULL,
PRIMARY KEY(WHID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE STOCKITEM7364(
StkID char(5),
StkName varchar(20),
SellingPrice number,
PurchasePrice number,
ManID char(5) NOT NULL,
WHID char(5) NOT NULL,
PRIMARY KEY(StkID),
FOREIGN KEY(ManID) REFERENCES MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES WAREHOUSE7364);
As far as I can tell, nothing of what you posted raises that error.
Additional drawback is the way you chose to create foreign key constraints. If you don't name it, Oracle assigns the name itself and it looks the way you posted it: SYSTEM.SYS_C007167.
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 foreign key (id_dept) references dept (deptno),
5 foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
SYS_C008172
SYS_C008173
SQL>
When one of these fails, looking at its name you have no idea what went wrong, unless you investigate a little bit more:
SQL> select column_name from user_cons_columns where constraint_name = 'SYS_C008173';
COLUMN_NAME
-----------------------
ID_EMP
SQL>
But, if you name the constraint, it is way simpler:
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 constraint fk_test_dept foreign key (id_dept) references dept (deptno),
5 constraint fk_test_emp foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
FK_TEST_DEPT
FK_TEST_EMP
SQL>
Another major drawback one notices is what's written in front of the dot, here: SYSTEM.SYS_C007167. Yes, that would be SYSTEM. Shortly, don't do that. Leave SYS and SYSTEM alone; they are powerful, they are special. Why would you take the risk of destroying the database if you (un)intentionally do something hazardous? Create another user, grant required privileges and work in that schema.
If I understood you correctly, once you create that temp table (TEMP_TAB7364), its contents is transferred into the DW_ITEMS7364 and - doing so - you hit the error.
If that's so, what's the purpose of the temp table? Insert directly into the target table and save resources. Will it fail? Of course it will, unless you change the query. How? I don't know - make sure that you don't insert values that don't exist in any of three tables used for enforcing referential integrity.
Though, as you already have the temp table, if it isn't too large, a (relatively) quick & dirty way of finding out which row is responsible for the error can be found with a loop, such as
begin
for cur_r in (select col1, col2, ... from temp_table) loop
begin
insert into target (col1, col2, ...)
values (cur_r.col1, cur_r.col2, ...);
exception
when others then
dbms_output.put_line(sqlerrm ||': '|| cur_r.col1 ||', '||cur_r.col2);
end;
end loop;
end;
The inner BEGIN-END block is here to make sure that the PL/SQL code won't exit at the first error, but will display them all. Then review those values and find the reason that makes your query invalid.

Basic primary key / foreign key with constraint, sequence, trigger

Learner here in Oracle 11g. I'm having an issue with INSERTing some rows into two tables that are linked by a primary/foreign key relationship.
Basically I create a sequence to start with 1000 and increment by 1.
Then create a 'STORE' table with a ST_ID column
The ST_ID column is linked to the SEQUENCE with a TRIGGER.
Then I have an 'EMPLOYEE' table that has a EST_ID field that is a foreign key to the ST_ID column in the STORE table.
However, when I tried to insert rows I initially got a error saying EST_ID could not be null. So I created a sequence and trigger for EST_ID and now I'm getting an error saying the foreign key constraint is being violated.
I think that was maybe the wrong thing to do. Do I really want E_ID and EST_ID to be identical and how would I get that to happen? With some kind of trigger?
The actual code:
CREATE SEQUENCE "STORSEQ" MINVALUE 1000 MAXVALUE 9999 INCREMENT BY 1 START WITH 1000 NOCACHE NOORDER
NOCYCLE ;
CREATE TABLE "STORE"
( "ST_ID" CHAR(4) NOT NULL ENABLE,
"STADDR_ID" CHAR(4) NOT NULL ENABLE,
CONSTRAINT "STORE_PK" PRIMARY KEY ("ST_ID") ENABLE
) ;
CREATE TABLE "EMPLOYEE"
( "E_ID" CHAR(8) NOT NULL ENABLE,
"EF_NAME" VARCHAR2(20) NOT NULL ENABLE,
"EL_NAME" VARCHAR2(20) NOT NULL ENABLE,
"EST_ID" CHAR(4) NOT NULL ENABLE,
CONSTRAINT "EMPLOYEE_PK" PRIMARY KEY ("E_ID") ENABLE
) ;
alter table "EMPLOYEE" add CONSTRAINT "EMPLOYEE_CON" foreign key ("EST_ID") references
"STORE" ("ST_ID")
/
CREATE OR REPLACE TRIGGER "BI_STORE"
before insert on "STORE"
for each row
begin
if :NEW."ST_ID" is null then
select "STORSEQ".nextval into :NEW."ST_ID" from dual;
end if;
end;
/
At the moment my INSERT code looks like this:
INSERT INTO STORE
(ST_ID, STADDR_ID)
VALUES
(DEFAULT, DEFAULT);
INSERT INTO EMPLOYEE
(EF_NAME, EL_NAME)
VALUES
('James', 'Smith');
When you try to insert data into table that has foreign key reference, it will not get value for id automatically, you need to pass that value.
You can do this:
declare
v_store_id integer;
begin
INSERT INTO STORE (ST_ID, STADDR_ID) VALUES (DEFAULT, DEFAULT)
RETURNING ST_ID INTO v_Store_id;
INSERT INTO EMPLOYEE (EF_NAME, EL_NAME, EST_ID)
VALUES ('James', 'Smith', v_store_id);
end;
You can also insert id in store id table without trigger using this
declare
v_store_id integer;
begin
INSERT INTO STORE (ST_ID, STADDR_ID) VALUES ("STORSEQ".nextval, DEFAULT)
RETURNING ST_ID INTO v_Store_id;
INSERT INTO EMPLOYEE (EF_NAME, EL_NAME, EST_ID)
VALUES ('James', 'Smith', v_store_id);
end