I have problem with Enforcing Referential Integrity to a new table.
There are different tables in different schemas, each one has its primary key:
schema1.table1
schema2.table2
schema3.table3
I want to create a new table, which among other information and its primary id, has a column "reference_schema" and a column "reference_id".
I want the column "referencing id" to reference the id on the relevant table, that is of the "reference_schema"="schema1" to reference the primary key schema1.table1.id.
The primary keys on the 3 tables, aren't unique in a UNION.
I have tried synthesizing a primary key in a UNION ALL view, but Oracle does not enforce view constraints.
It is not the different schema that causes problems, but the fact that you can't create a foreign key constraint which would reference two (or more) different tables.
I mean, you can do it, using out-of-line constraint syntax, but that just won't work. Why? Because - if that value doesn't exist in all referenced tables, constraint will be violated.
create table new_table
(id number constraint pk_newtab primary key,
ref_schema varchar2(30),
ref_id number,
--
constraint fk_newtab_s1 foreign key (ref_id) references schema1.table1 (id),
constraint fk_newtab_s2 foreign key (ref_id) references schema2.table2 (id)
);
A simple example is Scott's sample schema (there is department number 10, but no employee has that EMPNO):
SQL> create table test
2 (id number,
3 constraint fk1 foreign key (id) references scott.dept (deptno),
4 constraint fk2 foreign key (id) references scott.emp (empno)
5 );
Table created.
SQL> insert into test (id) values (10);
insert into test (id) values (10)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.FK2) violated - parent key not found
SQL>
So, what can you do? Use a trigger. Something like this:
SQL> create or replace trigger trg_test
2 before insert or update on test
3 for each row
4 declare
5 l_cnt number;
6 begin
7 select deptno into l_cnt
8 from dept
9 where deptno = :new.id;
10
11 exception
12 when no_data_found then
13 begin
14 select empno into l_cnt
15 from emp
16 where empno = :new.id;
17
18 exception
19 when no_data_found then
20 raise_application_error(-20000, 'Foreign key does not exist in any referenced table');
21 end;
22 end;
23 /
Trigger created.
Testing:
SQL> insert into test (id) values (10); --> this is ACCOUNTING
1 row created.
SQL> insert into test (id) values (7369); --> this is SMITH
1 row created.
SQL> insert into test (id) values (99); --> this doesn't exist in any table
insert into test (id) values (99)
*
ERROR at line 1:
ORA-20000: Foreign key does not exist in any referenced table
ORA-06512: at "SCOTT.TRG_TEST", line 17
ORA-04088: error during execution of trigger 'SCOTT.TRG_TEST'
SQL>
From Oracle 12, you can use virtual columns and put the constraints on the virtual column.
For example, if you have the tables:
CREATE TABLE table1 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table2 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table3 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
Then you can create your table as:
CREATE TABLE new_table(
id NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
reference_table VARCHAR2(30)
CHECK (reference_table IN ('table1', 'table2', 'table3')),
reference_id NUMBER
NOT NULL,
t1_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table1' THEN reference_id END
)
REFERENCES table1(id),
t2_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table2' THEN reference_id END
)
REFERENCES table2(id),
t3_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table3' THEN reference_id END
)
REFERENCES table3(id)
);
Note: If you want to change from different tables in the same schema to the same table in different schemas then just update the foreign key constraint to point to the correct location.
db<>fiddle here
I am creating this code SQL code and I keep getting the same error from every line of the insert statements after the errors begin here statement. the error is, ORA-02291: integrity constraint violated - parent key not found. I think it has something to do with the employee section constraint EMPSUPERVRFK but, that is the only constraint that the error message would lead to.
-- keep these two commands at the top of every sql file
set echo on
set linesize 120
delete from Employee;
commit;
-- insert only managers first with their dno is null
INSERT INTO Employee VALUES
('James','E','Borg',888665555,'10-NOV-1937','450 Stone, Houston, TX','M',55000,null,null);
INSERT INTO Employee VALUES
('Franklin','T','Wong',333445555, to_date('1955-12-08', 'YYYY-MM-DD'), '638 Voss, Houston, TX','M',40000,888665555,null);
INSERT INTO Employee VALUES
('Jennifer','J','Zelaya',987654321,'20-JUN-1941','291 Berry, Bellaire, TX','F',43000,888665555,null);
delete from Department;
commit;
insert into Department values ('Research',5,333445555,'22-MAY-1988');
insert into Department values ('Headquarters',1,888665555,'19-JUN-1981');
insert into Department values ('Administration',1,888665555,'01-JAN-1995');
-- now, update employee.dno for managers
UPDATE Employee SET dno = 1 WHERE ssn = 888665555;
UPDATE Employee SET dno = 5 WHERE ssn = 333445555;
-- need to update the rest of managers
-- insert the rest of non-manager employees, supervisors first
--errors begin here
delete from Employee;
commit;
INSERT INTO Employee VALUES ('John','B','Smith',123456789,'09-JAN-1965','731 Fondren, Houston, TX','M',30000,333445555,5);
insert into Employee values ('Alica','J','Zelya',999887777,'19-JAN-1968','3321 Castle, Spring, TX','F',25000,987654321,4);
insert into Employee values ('Ramesh','K','Narayan',666884444,'15-SEP-1962', '975 Fire Oak, Humnle, TX','M',38000,333445555,5);
insert into Employee values ('Joyce','A','English',453453453,'31-JUL-1972','5631 Rice, Houston, TX','F',25000,333445555,5);
insert into Employee values ('Ahmad','V','Jabbar',987987987,'29-MAR-1969','980 Dallas, Houston, TC','M',25000,987654321,4);
--Project
delete from PROJECT;
commit;
insert into PROJECT values ('ProductY',2,'Sugarland',5);
insert into PROJECT values ('ProductZ',3,'Houston',5);
insert into PROJECT values ('Computerication',10,'Stafford',4);
insert into PROJECT values ('Reorganization',20,'Houston',1);
insert into PROJECT values ('Newbenefits',30,'Stafford',4);
--dept_Locations
delete from DEPT_LOCATIONS;
commit;
insert into DEPT_LOCATIONS values (1, 'Houston');
insert into DEPT_LOCATIONS values (4,'Stafford');
insert into DEPT_LOCATIONS values (5,'Bellaire');
insert into DEPT_LOCATIONS values (5,'Sugarland');
insert into DEPT_LOCATIONS values (5,'Houston');
--works_on 16
delete from WORKS_ON;
commit;
insert into WORKS_ON values (123456789,1,32.5);
insert into WORKS_ON values (123456789,2,7.5);
insert into WORKS_ON values (666884444,3,40.0);
insert into WORKS_ON values (453453453,1,20.0);
insert into WORKS_ON values (453453453,2,20.0);
insert into WORKS_ON values (333445555,2,10.0);
insert into WORKS_ON values (333445555,3,10.0);
insert into WORKS_ON values (333445555,10,10.0);
insert into WORKS_ON values (333445555,20,10.0);
insert into WORKS_ON values (999887777,30,30.0);
insert into WORKS_ON values (999887777,10,10.0);
insert into WORKS_ON values (987987987,10,35.0);
insert into WORKS_ON values (987987987,30,5.0);
insert into WORKS_ON values (987654321,30,20.0);
insert into WORKS_ON values (987654321,20,15.0);
insert into WORKS_ON values (888665555,20,null);
--dependent 7
delete from DEPENDENT;
commit;
insert into DEPENDENT values (333445555,'Alice','F','05-APR-1986','Daughter');
insert into DEPENDENT values (333445555,'Theodore','M','25-OCT-1983','Son');
insert into DEPENDENT values (333445555,'Joy','F', '03-MAY-1958','Spouse');
insert into DEPENDENT values (987654321,'Abner','M', '28-FEB-1942','Spouse');
insert into DEPENDENT values (123456789,'Michael','M','04-JAN-1988','Son');
insert into DEPENDENT values (123456789,'Alice','F','30-DEC-1988','Daughter');
insert into DEPENDENT values (123456789,'Elizabeth','F', '05-MAY-1967','Spouse');
-----------------------------------------------------------------------------------
set echo on
set linesize 120
drop table Employee cascade constraints;
commit;
create table Employee
(
fname varchar2(15),
minit varchar2(1), -- can be char
lname varchar2(15),
ssn number,
bdate date,
address varchar2(50),
sex varchar2(1) CHECK(Sex = 'M' or Sex = 'F'),
salary number CHECK(20000 <= salary AND 100000 >= salary),
superssn number,
dno number DEFAULT 0,
constraint EMPPK
primary key(ssn),
constraint EMPSUPERVRFK
foreign key(superssn) references Employee(ssn)
ON DELETE SET NULL
);
drop table Department cascade constraints;
commit;
create table Department
(
dname varchar2(15),-- NOT NULL,
dnumber number,
mgrssn number,
mgrstartdate date,
constraint DEPTPK
primary key(dnumber),
constraint DEPTMGRFK
foreign key(mgrssn) references Employee(ssn)
ON DELETE SET NULL
);
alter table Employee add
constraint EMPDEPTFK foreign key(dno) references Department(dnumber)
ON DELETE SET NULL;
drop table DEPT_LOCATIONS;
create table DEPT_LOCATIONS
(
Dnumber number,
Dlocation varchar2(15),
constraint PK_DnoDloc primary key(Dnumber,Dlocation)
);
COMMIT;
drop table PROJECT;
create table PROJECT
(
Pname varchar2(15),
Ponumber number primary key,
Plocation varchar2 (15),
Dnum number,
foreign key (Dnum) references Department(dnumber)
);
Commit;
drop table DEPENDENT;
create table DEPENDENT
(
Essn number,
Dependent_name varchar2(15),
Sex Char,
Bdate Date,
Relationship varchar2(15),
foreign key(Essn) references Employee(ssn) --
ON DELETE SET NULL,
constraint PK_essn
primary key(Essn,Dependent_name)
);
COMMIT;
drop table WORKS_ON;
create table WORKS_ON
(
Essn number,
Pno number,
Hours number,
foreign key(Essn) references Employee(ssn)--
ON DELETE SET NULL,
foreign key(Pno) references PROJECT(Ponumber)
ON DELETE SET NULL,
constraint PK_SSN
primary key(Essn, Pno)
);
commit;
----------------------------------------------------------------
-- keep these two commands at the top of every sql file
set echo on
set linesize 120
-- test queries, not to be submitted
select count(*) from employee;
select count(*) as DEPT_COUNT from department;
-- comment out the above queries for your homework
-- a the first name, last name of employees who work in department 5.
select fname, lname from employee where dno = 5;
-- b the first name, last name of every employee and name of his/her department
select E.fname as FIRST_NAME, E.lname LAST_NAME, D.dname DEPARTMENT_NAME
from employee E, department D
where E.dno = D.dnumber;
--c The first name, last name of employees who works at the 'Research' department
select e.fname , e.lname , Dname
from employee e inner join department d on e.dno=d.dname
where d.name ='Research';
--d. The first name, last name of employee who is the manager of the 'Research' department
select e.fname , e.lname , Dname
from employee e inner join department d on e.dno=d.dname
where d.name ='Research' and e.super_ssn=d.mgr_ssn;
--e. The first name, last name of employees who works on the 'Computerization' project.
select e.fname,e.lname
from employee e inner join department d on e.dno=d.dnumber inner join project p on d.dnumber=p.dnum
where p.pname="Computerization";
this happens because you are inserting values to table that depends on other table that is still empty, you should insert on that table first before this one
for example, suppose you have employee table, and department table, in which every employee must be assigned to a department, so when you input employee Bob to department IT, it would result in error, since there is no IT yet in department table. so you need to input IT on department table, then you can input Bob to employee table
or, you can disable integrity check when importing sql, but this setting is different for each DB engine, so I can't give you an example
I have a table with one column of type Identity Column, which is also the primary key.
CREATE TABLE identity_demo (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
description VARCHAR2(100) not null
);
then I insert a few lines of data
insert into identity_demo (id, description) values (1,'A');
insert into identity_demo (id, description) values (2,'B');
insert into identity_demo (id, description) values (3,'C');
insert into identity_demo (id, description) values (4,'D');
insert into identity_demo (id, description) values (5,'E');
insert into identity_demo (id, description) values (6,'F');
if I now want to insert a row for which the value ID is not set, I get a key violation
insert into identity_demo (description) values ('G');
ORA-00001: Unique Constraint (UWE.IDENTITY_DEMO_PK) verletzt
what's the best way to proceed here?
First of all, seems that there's a part , CONSTRAINT IDENTITY_DEMO_PK PRIMARY KEY (id)
added to the end of the table creation DDL.
Just remove BY DEFAULT ON NULL part in order to leave the management of identity generation to the DBMS while keeping ID column as a PRIMARY KEY. In this case, you should remove ID column from the column list within the Insert Statement like in
INSERT INTO identity_demo (description) VALUES ('G'); :
SQL> CREATE TABLE identity_demo (
2 id NUMBER GENERATED AS IDENTITY,
3 description VARCHAR2(100) NOT NULL,
4 CONSTRAINT IDENTITY_DEMO_PK PRIMARY KEY (id)
5 );
Table created
SQL> BEGIN
2 INSERT INTO identity_demo (id, description) VALUES (1,'A');
3 INSERT INTO identity_demo (id, description) VALUES (2,'B');
4 INSERT INTO identity_demo (id, description) VALUES (3,'C');
5 INSERT INTO identity_demo (id, description) VALUES (4,'D');
6 INSERT INTO identity_demo (id, description) VALUES (5,'E');
7 INSERT INTO identity_demo (id, description) VALUES (6,'F');
8 END;
9 /
ORA-32795: cannot insert into a generated always identity column
ORA-06512: at line 3
SQL> INSERT INTO identity_demo (description) VALUES ('G');
1 row inserted
SQL> SELECT * FROM identity_demo;
ID DESCRIPTION
---------- -------------------------------------------------------
1 G
SQL> BEGIN
2 INSERT INTO identity_demo (description) VALUES ('A');
3 INSERT INTO identity_demo (description) VALUES ('B');
4 INSERT INTO identity_demo (description) VALUES ('C');
5 INSERT INTO identity_demo (description) VALUES ('D');
6 INSERT INTO identity_demo (description) VALUES ('E');
7 INSERT INTO identity_demo (description) VALUES ('F');
8 END;
9 /
PL/SQL procedure successfully completed
SQL> SELECT * FROM identity_demo;
ID DESCRIPTION
---------- --------------------------------------------------------
1 G
2 A
3 B
4 C
5 D
6 E
7 F
7 rows selected
You got a collision between the identity values that you have inserted manually (1 to 6) and the identity value that the sequence generator produced. You can fix it by adjusting the sequence generator:
ALTER TABLE identity_demo MODIFY (
id GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH LIMIT VALUE));
The START WITH LIMIT VALUE locks the table, finds the highest id and sets the internal sequence generator to the next higher value 7.
If you don't want to run this ALTER TABLE command, you could separate the number spaces, say 1...999 for manual values and 1000... for automatic values. You have to set up your generator like thus:
ALTER TABLE identity_demo MODIFY (
id GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1000));
INSERT INTO identity_demo (description) VALUES ('H');
...
6 F
7 G
1000 H
I created the following table
CREATE TABLE PLACE(
POSTCODE VARCHAR(10) PRIMARY KEY,
STREET_NAME VARCHAR(10),
COUNTY VARCHAR(10),
CITY VARCHAR(10));
I want to change the name, county and city from varchar(10) to varchar(20). How do I do that?
ALTER TABLE place
MODIFY( street_name VARCHAR2(20),
county VARCHAR2(20),
city VARCHAR2(20) )
Note that I am also changing the data type from VARCHAR to VARCHAR2 to be more conventional. There is no functional difference at present between the two though the behavior of VARCHAR may change in the future to match the SQL standard.
if you want to change only type of column use below:
ALTER TABLE <table_name> MODIFY (<column_name> <new_Type>)
in your case:
ALTER TABLE place MODIFY (street_name VARCHAR2(20),
county VARCHAR2(20),
city VARCHAR2(20))
If your table has data you could act below:
add a column with new type to table.
copy data from old column to new column.
drop old column.
rename new column to old.
For rename a column use below:
ALTER TABLE <table_name> rename column <column_name> to <new_column_name>
Oracle 10G and later
ALTER TABLE table_name
MODIFY column_name datatype;
A very general example is here to do the same -
Table:
CREATE TABLE TABLE_NAME(
ID NUMBER PRIMARY KEY,
COLUMN_NAME NUMBER NOT NULL, -- Modify with varchar2(20) NOT NULL
.
.
.
);
Step to modify the datatype of COLUMN_NAME from NUMBER to VARCHAR2
STEPS:
--Step 1: Add a temp column COLUMN_NAME_TEMP in table TABLE_NAME to hold data temporary
ALTER TABLE TABLE_NAME
ADD( COLUMN_NAME_TEMP varchar2(20) );
--Step 2: Update temp column COLUMN_NAME_TEMP with Old columns COLUMN_NAME data
UPDATE TABLE_NAME
SET COLUMN_NAME_TEMP = COLUMN_NAME;
--Step 3: Remove NOT NULL constrain from old columns COLUMN_NAME
ALTER TABLE TABLE_NAME MODIFY (COLUMN_NAME NULL);
--Step 4: Update old columns COLUMN_NAME data with NULL
UPDATE TABLE_NAME SET COLUMN_NAME = NULL;
--Step 5: Alter table old columns COLUMN_NAME to new data type varchar2(20)
ALTER TABLE TABLE_NAME MODIFY COLUMN_NAME varchar2(20);
--Step 6: Update old columns COLUMN_NAME with data from temp columns COLUMN_NAME_TEMP
UPDATE TABLE_NAME
SET COLUMN_NAME = COLUMN_NAME_TEMP;
--Step 7: Add NOT NULL constrain from old columns [COLUMN_NAME]
ALTER TABLE TABLE_NAME MODIFY (COLUMN_NAME NOT NULL);
--Step 8: Drop the temp column [COLUMN_NAME_TEMP]
alter table TABLE_NAME drop column COLUMN_NAME_TEMP;
If NOT NULL constrain is not exist the omitte step-3 and step-7
Alter table placemodify(street name varchar2(20),city varchar2(20)
You can't modify the data type of a table if you have some amount of records already present in the table.
You have to empty the table records of the column (you want to modify the data type) first and then use the below command :
alter table place
modify ( street_name varchar2(20), country varchar2(20), city varchar2(20) );
Definitely it will work!