I haven't tried this yet, it's part of a 90+ tables schema that I'm rebuilding and I was wondering if the logic was right. I have two tables which contain data and a third one that joins PKs from them:
CREATE TABLE TABLE1
(
USER_ID NUMBER(9),
DEPARTMENT_ID NUMBER(9),
DESK_ID NUMBER(9),
FULLNAME VARCHAR2(12),
CONSTRAINT PK_TABLE1 PRIMARY KEY (USER_ID, DEPARTMENT_ID, DESK_ID)
);
CREATE TABLE TABLE2
(
USER_ID NUMBER(9),
BUILDING_ID NUMBER(9),
PARKING_ID NUMBER(9),
LICENSE_PLATE VARCHAR2(10),
CONSTRAINT PK_TABLE2 PRIMARY KEY (USER_ID, BUILDING_ID, PARKING_ID)
);
CREATE TABLE TABLE3
(
USER_ID NUMBER(9),
DEPARTMENT_ID NUMBER(9),
DESK_ID NUMBER(9),
BUILDING_ID NUMBER(9),
PARKING_ID NUMBER(9),
CONSTRAINT PK_TABLE3 PRIMARY KEY (USER_ID, DEPARTMENT_ID, DESK_ID, BUILDING_ID, PARKING_ID),
CONSTRAINT FK_TABLE3_T1 FOREIGN KEY (USER_ID, DEPARTMENT_ID, DESK_ID) REFERENCES TABLE1(USER_ID, DEPARTMENT_ID, DESK_ID),
CONSTRAINT FK_TABLE3_T2 FOREIGN KEY (USER_ID, BUILDING_ID, PARKING_ID) REFERENCES TABLE2(USER_ID, BUILDING_ID, PARKING_ID)
);
Is it right? Can the same column TABLE3.USER_ID be part of two FKs?
Thanks
Yes you can, even with the same column list.
Try this:
CREATE TABLE T1
(C1 NUMBER PRIMARY KEY);
CREATE TABLE T2
(C1 NUMBER PRIMARY KEY);
CREATE TABLE T3
(C1 NUMBER PRIMARY KEY);
Populate T1 and T2 with some values:
INSERT INTO T1 VALUES(1);
INSERT INTO T1 VALUES(2);
INSERT INTO T2 VALUES(1);
INSERT INTO T2 VALUES(3);
Create two identical constraints from T3 to T1 and T2:
ALTER TABLE T3
ADD CONSTRAINT FK1 FOREIGN KEY (C1) REFERENCES T1(C1);
ALTER TABLE T3
ADD CONSTRAINT FK2 FOREIGN KEY (C1) REFERENCES T2(C1);
And now...
INSERT INTO T3 VALUES(1); -- Succeeds (1 is in both T1 and T2)
INSERT INTO T3 VALUES(2); -- Fails (2 is only in T1 and violates FK2)
Clean your environment:
DROP TABLE T3 PURGE;
DROP TABLE T1 PURGE;
DROP TABLE T2 PURGE;
I hope this helps you...
Related
Example Oracle SQL Code:
create table t1 (
t1a integer,
t1b varchar2(30)
);
alter table t1 add constraint t1_pk primary key (t1a);
insert into t1 values (1, 'A');
insert into t1 values (2, 'B');
create table t11 (
t11a integer,
t1a integer,
t11b varchar2(30)
);
alter table t11 add constraint t11_pk primary key (t11a);
alter table t11 add constraint t11_t1_fk foreign key (t1a) references t1(t1a);
insert into t11 values (10, 1, 'A1');
insert into t11 values (11, 2, 'B1');
create table t12 (
t12a integer,
t1a integer,
t12b varchar2(30)
);
alter table t12 add constraint t12_pk primary key (t12a);
alter table t12 add constraint t12_t1_fk foreign key (t1a) references t1(t1a);
insert into t12 values (20, 1, 'A2');
insert into t12 values (21, 2, 'B2');
create table t1112 (
t11a integer,
t12a integer
);
alter table t1112 add constraint t1112_pk primary key (t11a, t12a);
alter table t1112 add constraint t1112_t11_fk foreign key (t11a) references t11(t11a);
alter table t1112 add constraint t1112_t12_fk foreign key (t12a) references t12(t12a);
create or replace trigger t1112_trg before insert or update on t1112 for each row
declare
t11a_v integer;
t12a_v integer;
begin
select t11.t1a into t11a_v from t11 where t11.t11a = :new.t11a;
select t12.t1a into t12a_v from t12 where t12.t12a = :new.t12a;
if (t11a_v != t12a_v) then
raise_application_error(-20000, 'Mismatch');
end if;
end;
/
Top level table: t1.
t11 and t12 have a foreign key reference to t1.
t1112 is an intersection table between t1 and t2.
I want to ensure that any rows written into t1112 have a combination of t11 and t12 such that they both point to the same row in t1.
I have tried to implement it with a trigger in the example. Is there a way to do this via referential integrity constraints?
The easiest way is to create additional unique constraints on tables t11 and t12:
ALTER TABLE t11 ADD CONSTRAINT t11_un UNIQUE ( t11a, t1a );
ALTER TABLE t12 ADD CONSTRAINT t12_un UNIQUE ( t12a, t1a );
Add column t1a to table T1112
ALTER TABLE t1112 ADD (t1a integer);
Drop and recreate your foreign key constraints on t1112:
ALTER TABLE T1112 DROP CONSTRAINT T1112_T11_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T11_FK FOREIGN KEY (t11a, t1a ) REFERENCES T11 (t11a, t1a);
ALTER TABLE T1112 DROP CONSTRAINT T1112_T12_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T12_FK FOREIGN KEY (t12a, t1a ) REFERENCES T12 (t12a, t1a);
Such that they now use the two unique constraints instead of the primary keys. The shared column t1a in the join table will ensure that the keys from t11 and t12 join back to t1.
Use a materialized view:
CREATE MATERIALIZED VIEW t11_t12_mv
BUILD IMMEDIATE
AS SELECT t11a, t12a
FROM t11 INNER JOIN t12 ON t11.t1a = t12.t1a;
ALTER TABLE t11_t12_mv ADD CONSTRAINT t11a_t12a__pk PRIMARY KEY ( t11a, t12a );
create table t1112 (
t11a integer,
t12a integer,
CONSTRAINT t1112_pk PRIMARY KEY (t11a, t12a),
CONSTRAINT t1112_fk FOREIGN KEY (t11a, t12a) REFERENCES t11_t12_mv ( t11a, t12a )
);
Then:
INSERT INTO t1112 VALUES ( 10, 20 );
INSERT INTO t1112 VALUES ( 11, 21 );
Works. However:
INSERT INTO t1112 VALUES ( 10, 21 );
Raises the exception:
ORA-02291: integrity constraint (USER_4_F249D.T1112_FK) violated - parent key not found
sqlfiddle here
I am trying to move data from parent table which is interval partitioned, and a child table partitioned by reference, into corresponding archive table structure.
And to my suprise this seemingly simple task is beyond my reach...
I have read about moving partitioned table to archive but it do not tell how to move tables with foregin keys.
I also read about moving reference partitioned tables, but this solution does not work for me, giving this error after first statement:
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
So, I have tried my own approach. It gives me even worse error:
ORA-00600: internal error code, arguments: [kkpamRefGet: index], [], [], [], [], [], [], [], [], [], [], []
You can reproduce my latest attempt like this:
/*
DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
*/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE_ARCHIVE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
-- My last attempt to do this
ALTER TABLE CHILD_TABLE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting: ORA-14130: UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting: ORA-14128: FOREIGN KEY constraint mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
/
-- And here is something starange...
ALTER TABLE CHILD_TABLE_ARCHIVE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/
Currently, I am out of ideas how should I do this, and I am starting to wonder should I even try to move this structure to archive... It is partitioned by dates, so can I just let it grow?
I would appreciate any help in this matter. :)
UPDATE:
Just as Francisco suggested, CASCADE option helped with my sample code. Below is my sample code in working condition.
But, in my real life scenario there is more than one child to parent table. And so, when I try to use CASCADe option I get ORA-14706. The proposed solution is not to use CASCADE option...
So I still can not archive my tables, and still really need help.
DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE_ARCHIVE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_TMP (PK)
ENABLE VALIDATE
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/
-----creating reference partitioning on existing tables having parent child relationship
----------------------------------------consider the following parent and child table---------------------------------------------------
--create the parent table:
create table t1(
id int,
action_date varchar(8),
constraint t1_pk primary key (id)
);
--create the child table table:
create table t2(
id int,
id_t1,
constraint t2_pk primary key (id),
constraint t2_fk1 foreign key (id_t1) references t1(id)
);
---insert sample data into parent
insert into t1 values(1,'20170801');
insert into t1 values(2,'20170901');
insert into t1 values(3,'20171001');
---insert sample data into child
insert into t2 values(1,1);
insert into t2 values(2,1);
insert into t2 values(3,1);
insert into t2 values(4,2);
insert into t2 values(5,1);
insert into t2 values(6,2);
insert into t2 values(7,3);
---------------------------------------------------------creating intermediate table for partitioning-----------------------------------------------------------------
-----------------parent table-------------------------
create table t1_part(
id int,
action_date varchar(8),
constraint t1_part_pk primary key (id)
) PARTITION BY RANGE (action_date)
(
PARTITION t1_part_old VALUES LESS THAN ('20171101'),
PARTITION t1_part_201711 VALUES LESS THAN ('20171201'),
PARTITION t1_part_201712 VALUES LESS THAN ('20180101'),
PARTITION t1_part_def VALUES LESS THAN ('99999999')
);
-------------------dropping constraints-----------------
ALTER TABLE t2 DROP constraint t2_fk1;
ALTER TABLE t1 DROP constraint t1_pk;
ALTER TABLE t1_part DROP constraint t1_part_pk;
desc t1;
desc t1_part;
-------------------------switch parent data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_old WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_def WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
ALTER TABLE t1_part add constraint t1_part_pk primary key (id);
--select * from t1_part;
drop table t1;
RENAME t1_part TO t1;
ALTER TABLE t1 RENAME CONSTRAINT t1_part_pk TO t1_pk;
ALTER TABLE t2 add constraint t2_fk1 foreign key (id_t1) references t1(id);
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
----------------------create partitioned child table---------------------------------------------
create table t2_part(
id int,
id_t1 not null,
constraint t2_part_pk primary key (id),
constraint t2_part_fk1 foreign key (id_t1) references t1(id)
) partition by reference (t2_part_fk1);
alter table t2 modify (id_t1 int not null);
desc t2;
desc t2_part
-------------------------switch child data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_old WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_def WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
--select * from t2_part;
drop table t2;
RENAME t2_part TO t2;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_pk TO t2_pk;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_fk1 TO t2_fk1;
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T2', cascade => TRUE);
-----------------------------------check partition info---------------------------------------------
select table_name, partition_name, high_value
from user_tab_partitions
where table_name in ('T1','T2');
desc t1;
desc t2;
-----------------add new parent partition, child partiion will automatically get created thorugh reference paritioning through foreign key t2_part_fk1
ALTER TABLE T1 SPLIT PARTITION t1_part_old AT ('20170701') INTO (PARTITION t1_part_old, PARTITION t1_part_201707) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201707 AT ('20170801') INTO (PARTITION t1_part_201707, PARTITION t1_part_201708) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201708 AT ('20170901') INTO (PARTITION t1_part_201708, PARTITION t1_part_201709) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201709 AT ('20171001') INTO (PARTITION t1_part_201709, PARTITION t1_part_201710) UPDATE GLOBAL INDEXES;
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
--------------------validating the partitioned data--------------------
select count(*) from T1 partition (T1_PART_OLD);
select * from T1 partition (T1_PART_201708);
select count(*) from T1 partition (T1_PART_201709);
select count(*) from T1 partition (T1_PART_201710);
select count(*) from T1 partition (T1_PART_201711);
select * from T2;
select * from T1;
select count(*) from T2 partition (T1_PART_OLD);
select * from T2 partition (T1_PART_201708);
select count(*) from T2 partition (T1_PART_201709);
select count(*) from T2 partition (T1_PART_201710);
select count(*) from T2 partition (T1_PART_201711);
-------truncate the partition T1_PART_201708 (refering the parent partition) and validate the data
alter table t2 truncate partition T1_PART_201708;
select * from t2; ----------------- data from 20170801 to 20170831 will be truncated from child
-------truncate the parent record
alter table t1 drop partition T1_PART_201708;
select * from t1;
I have two tables both of which reference each other primary keys as foreign keys, I want to drop both but I can't.
I tried this :
alter table my_table drop constraint cons_name;
That gave me :
ORA-02443: Cannot drop constraint - nonexistent constraint
Suppose you have the following tables (Oracle 12c) ...
create table table1 ( column1 primary key )
as
select level
from dual
connect by level <= 10 ;
create table table2 ( column1 primary key )
as
select level
from dual
connect by level <= 10 ;
alter table table1
add constraint fk1
foreign key ( column1 ) references table2( column1 ) ;
alter table table2
add constraint fk2
foreign key ( column1 ) references table1( column1 ) ;
If you want to remove the constraints, make sure that you use the correct
constraint names.
-- find the correct constraint names
select table_name, constraint_name, constraint_type
from user_constraints
where table_name in( 'TABLE1', 'TABLE2' ) ;
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
TABLE2 SYS_C0021482 P
TABLE1 SYS_C0021483 P
TABLE1 FK1 R
TABLE2 FK2 R
-- fails: constraint name correct, table name wrong
SQL> alter table table1 drop constraint SYS_C0021482;
ORA-02443: Cannot drop constraint - nonexistent constraint
-- fails: need to disable/remove the FK constraint first
SQL> alter table table1 drop constraint SYS_C0021483;
ORA-02273: this unique/primary key is referenced by some foreign keys
-- okay
SQL> alter table table1 drop constraint FK1 ;
Table TABLE1 altered.
If you just want to drop both tables, including all constraints, use ...
SQL> drop table table1 cascade constraints purge ;
Table TABLE1 dropped.
SQL> drop table table2 cascade constraints purge ;
Table TABLE2 dropped.
Check:
-- any constraints left? no.
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name in( 'TABLE1', 'TABLE2' ) ;
no rows selected
the procedure needs to ensure that:
1.The prerequisite courses for it (if any) already exist in the COURSE table. For simplicity,
we will pretend that a course can have at most one course as prerequisite.
The prerequisite for a course must be at a lower level. For instance, the prerequisite for ISYS326 must be a100- or 200-level course, and cannot be a 300 level course.
If either of the above requirements fails, the procedure raises an exception WRONG_PREREQ that prints an appropriate alert message, and does not modify the COURSE table.
in the procedure CID =courseid PID=prerequisiteid and DID=deptid they are all not null values
so this procedure will be used to enter new course
CREATE OR REPLACE PROCEDURE NEW_COURSE (
CID IN COURSE.COURSEID%TYPE,
CNAME IN COURSE.COURSENAME%TYPE,
PID IN HAS_PREREQUISITE.PREREQUISITEID%TYPE,
DID IN DEPARTMENT.DEPTID%TYPE
)
IS
CONDITION1 NUMBER;
CONDITION2 NUMBER;
WRONG_PREQ EXCEPTION;
BEGIN
/* this can be checked before any SQL */
IF (SUBSTR(CID,5,3) <= SUBSTR(PID,5,3)) THEN /*PREREQUISITE HAS A HIGHER ID
THAN COURSEID */
RAISE WRONG_PREQ;
END IF;
SELECT COUNT(COURSEID)
INTO CONDITION1
FROM COURSE
WHERE COURSEID = PID;
/* this can be checked here, without running the second select */
IF (CONDITION1 <>1) THEN /VIOLATION OF CONDITION 1, NO EXISTING
PREREQUISITE COURSE/
RAISE WRONG_PREQ;
END IF;
SELECT COUNT(*)
INTO CONDITION2
FROM HAS_PREREQUISITE
WHERE COURSEID = CID
AND PREREQUISITEID = PID
AND SUBSTR(CID,5,3) > SUBSTR(PID,5,3);
IF (CONDITION2 = 1) THEN /THE RECORD ALREADYS EXISTS IN HAS_PREREQUISITE
TABLE/
RAISE WRONG_PREQ;
END IF;
INSERT INTO COURSE VALUES(CID,CNAME,'NULL','NULL' );
INSERT INTO HAS_PREREQUISITE VALUES(CID,PID);
INSERT INTO DEPARTMENT VALUES (DEPTID,'NULL');
EXCEPTION
WHEN WRONG_PREQ THEN
DBMS_OUTPUT.PUT_LINE('COURSEID OR PREREQUISITE ID IS INVALID');
END NEW_COURSE;
This is done is Oracle SQL Developer.
DDL
/==============================================================/
/* DBMS name: ORACLE Version 11g */
/* Created on: 11/10/2016 3:47:29 PM */
/==============================================================/
alter table ACADEMIC_REC
drop constraint FK_ACADEMIC_RELATIONS_STUDENT;
alter table ACADEMIC_REC
drop constraint FK_ACADEMIC_RELATIONS_COURSE;
alter table COURSE
drop constraint FK_COURSE_OFFERS_DEPARTME;
alter table ENROLS
drop constraint FK_ENROLS_ENROLS_STUDENT;
alter table ENROLS
drop constraint FK_ENROLS_ENROLS2_TUT_PRAC;
alter table HAS_PREREQUISITE
drop constraint FK_HAS_PRER_HAS_PRERE_COURSE;
alter table HAS_PREREQUISITE
drop constraint FK_HAS_PRER_HAS_PRERE_COURSE;
alter table STAFF
drop constraint FK_STAFF_RELATIONS_DEPARTME;
alter table TEACHING_INFORMATION
drop constraint FK_TEACHING_RELATIONS_STAFF;
alter table TEACHING_INFORMATION
drop constraint FK_TEACHING_RELATIONS_COURSE;
alter table TUT_PRAC
drop constraint FK_TUT_PRAC_HAS_COURSE;
alter table TUT_PRAC
drop constraint FK_TUT_PRAC_RELATIONS_STAFF;
drop table ACADEMIC_REC cascade constraints;
drop table COURSE cascade constraints;
drop table ENROLS cascade constraints;
drop table HAS_PREREQUISITE cascade constraints;
drop table STAFF cascade constraints;
drop table STUDENT cascade constraints;
drop table TEACHING_INFORMATION cascade constraints;
drop table TUT_PRAC cascade constraints;
/==============================================================/
/* Table: ACADEMIC_REC */
/==============================================================/
create table ACADEMIC_REC
(
STUID CHAR(8) not null,
COURSEID CHAR(8) not null,
STATUS VARCHAR2(5),
YEAR NUMBER(4),
SEMESTER CHAR(2),
GRADE VARCHAR2(2)
constraint CKC_GRADE_ACADEMIC check (GRADE is null or (GRADE in
('HD','D','CR','P','F'))),
constraint PK_ACADEMIC_REC primary key (STUID, COURSEID)
);
/==============================================================/
/* Table: COURSE */
/==============================================================/
create table COURSE
(
COURSEID CHAR(8) not null,
DEPTID CHAR(8) not null,
COURSENAME VARCHAR2(20),
TEXTBOOK VARCHAR2(20),
CREDITHOUR NUMBER(2),
MAX_ENROL NUMBER(4),
ACTUAL_ENROL NUMBER(4),
AVAILABILITY NUMBER(4),
COURSE_TIME CHAR(7),
constraint PK_COURSE primary key (COURSEID)
);
/==============================================================/
/* Table: DEPARTMENT */
/==============================================================/
create table DEPARTMENT
(
DEPTID CHAR(8) not null,
DEPTNAME VARCHAR2(20),
DEPTCONTACTNO NUMBER(10),
BUILDING VARCHAR2(5),
constraint PK_DEPARTMENT primary key (DEPTID)
);
/==============================================================/
/* Table: ENROLS */
/==============================================================/
create table ENROLS
(
STUID CHAR(8) not null,
CLASSID CHAR(8) not null,
constraint PK_ENROLS primary key (STUID, CLASSID)
);
/==============================================================/
/* Table: HAS_PREREQUISITE */
/==============================================================/
create table HAS_PREREQUISITE
(
COURSEID CHAR(8) not null,
PREREQUISITEID CHAR(8) not null,
constraint PK_HAS_PREREQUISITE primary key (COURSEID, PREREQUISITEID)
);
/==============================================================/
/* Table: STAFF */
/==============================================================/
create table STAFF
(
STAFFID CHAR(8) not null,
DEPARTMENTID CHAR(8) not null,
STAFFNAME VARCHAR2(50),
STAFFADDRESS VARCHAR2(70),
STAFFCONTACTNO NUMBER(10),
STAFFEMAIL VARCHAR2(50),
OFFICENO NUMBER(5),
ROLE VARCHAR2(10),
constraint PK_STAFF primary key (STAFFID)
);
/==============================================================/
/* Table: STUDENT */
/==============================================================/
create table STUDENT
(
STUID CHAR(8) not null,
DEGREE VARCHAR2(10),
MAJOR VARCHAR2(10),
STU_NAME VARCHAR2(50),
STU_ADDRESS VARCHAR2(70),
CONTACTNO NUMBER(10),
EMAIL VARCHAR2(50),
constraint PK_STUDENT primary key (STUID)
);
/==============================================================/
/* Table: TEACHING_INFORMATION */
/==============================================================/
create table TEACHING_INFORMATION
(
STAFFID CHAR(8) not null,
COURSEID CHAR(8) not null,
SEMESTER CHAR(2) not null,
YEAR NUMBER(4) not null,
constraint PK_TEACHING_INFORMATION primary key (STAFFID, COURSEID, SEMESTER, YEAR)
);
/==============================================================/
/* Table: TUT_PRAC */
/==============================================================/
create table TUT_PRAC
(
CLASSID CHAR(8) not null,
COURSEID CHAR(8) not null,
STAFFID CHAR(8) not null,
TYPE VARCHAR2(5),
DAY VARCHAR2(10),
TIME DATE,
ROOMID CHAR(10),
NO_OF_SEATS NUMBER(2),
constraint PK_TUT_PRAC primary key (CLASSID)
);
alter table ACADEMIC_REC
add constraint FK_ACADEMIC_RELATIONS_STUDENT foreign key (STUID)
references STUDENT (STUID);
alter table ACADEMIC_REC
add constraint FK_ACADEMIC_RELATIONS_COURSE foreign key (COURSEID)
references COURSE (COURSEID);
alter table COURSE
add constraint FK_COURSE_OFFERS_DEPARTME foreign key (DEPTID)
references DEPARTMENT (DEPTID);
alter table ENROLS
add constraint FK_ENROLS_ENROLS_STUDENT foreign key (STUID)
references STUDENT (STUID);
alter table ENROLS
add constraint FK_ENROLS_ENROLS2_TUT_PRAC foreign key (CLASSID)
references TUT_PRAC (CLASSID);
alter table HAS_PREREQUISITE
add constraint FK_HAS_PRER_HAS_PRERE_COURSE foreign key (COURSEID)
references COURSE (COURSEID);
alter table HAS_PREREQUISITE
add constraint FK_HAS_PRER_HAS_PRERE_COURSE foreign key (PREREQUISITEID)
references COURSE (COURSEID);
alter table STAFF
add constraint FK_STAFF_RELATIONS_DEPARTME foreign key (DEPARTMENTID)
references DEPARTMENT (DEPTID);
alter table TEACHING_INFORMATION
add constraint FK_TEACHING_RELATIONS_STAFF foreign key (STAFFID)
references STAFF (STAFFID);
alter table TEACHING_INFORMATION
add constraint FK_TEACHING_RELATIONS_COURSE foreign key (COURSEID)
references COURSE (COURSEID);
alter table TUT_PRAC
add constraint FK_TUT_PRAC_HAS_COURSE foreign key (COURSEID)
references COURSE (COURSEID);
alter table TUT_PRAC
add constraint FK_TUT_PRAC_RELATIONS_STAFF foreign key (STAFFID)
references STAFF (STAFFID);
Well you have clear error message. All regarding following tables:
The first table say not enough values. It means you try insert less values than columns in table
INSERT INTO COURSE VALUES(CID,CNAME,'NULL','NULL' );
-- Error(29,3): PL/SQL: SQL Statement ignored Error(29,15): PL/SQL: ORA-00947: not enough values
You may add values or specify a columns for instance `INSERT INTO COURSE (course_id, course_name, val1, val2 ) VALUES(CID,CNAME,'NULL','NULL' );`
Next;
INSERT INTO HAS_PREREQUISITE VALUES(CID,PID,'NULL','NULL');
-- Error(30,3): PL/SQL: SQL Statement ignored Error(30,15): PL/SQL: ORA-00913: too many values
Its clear too. table HAS_PREREQUISITE has less columns then you try to insert. Delete extra values
INSERT INTO DEPARTMENT VALUES (DEPTID,'NULL');
-- Error(31,3): PL/SQL: SQL Statement ignored Error(31,15): PL/SQL: ORA-00947: not enough values
Is the same as first example.
I tried to edit your code moving some checks around to avoid unuseful queries and showing you what to edit; follow the comments:
CREATE OR REPLACE PROCEDURE NEW_COURSE (
CID IN COURSE.COURSEID%TYPE,
CNAME IN COURSE.COURSENAME%TYPE,
PID IN HAS_PREREQUISITE.PREREQUISITEID%TYPE,
DID IN DEPARTMENT.DEPTID%TYPE
)
IS
CONDITION1 NUMBER;
CONDITION2 NUMBER;
WRONG_PREQ EXCEPTION;
BEGIN
/* this can be checked before any SQL */
IF (SUBSTR(CID,5,3) <= SUBSTR(PID,5,3)) THEN /*PREREQUISITE HAS A HIGHER ID THAN COURSEID */
RAISE WRONG_PREQ;
END IF;
SELECT COUNT(COURSEID)
INTO CONDITION1
FROM COURSE
WHERE COURSEID = PID;
/* this can be checked here, without running the second select */
IF (CONDITION1 <>1) THEN /*VIOLATION OF CONDITION 1, NO EXISTING
PREREQUISITE COURSE*/
RAISE WRONG_PREQ;
END IF;
SELECT COUNT(*)
INTO CONDITION2
FROM HAS_PREREQUISITE
WHERE COURSEID = CID
AND PREREQUISITEID = PID
AND SUBSTR(CID,5,3) > SUBSTR(PID,5,3);
IF (CONDITION2 = 1) THEN /*THE RECORD ALREADYS EXISTS IN HAS_PREREQUISITE
TABLE*/
RAISE WRONG_PREQ;
END IF;
INSERT INTO COURSE VALUES(CID,CNAME,'NULL','NULL' ); /* edit the statement to fit the table structure also 'NULL' or null ?*/
INSERT INTO HAS_PREREQUISITE VALUES(CID,PID); /* the table only has 2 colums */
INSERT INTO DEPARTMENT VALUES (DEPTID,'NULL'); /* edit the statement to fit the table structure. also 'NULL' or null ? */
EXCEPTION
WHEN WRONG_PREQ THEN
DBMS_OUTPUT.PUT_LINE('COURSEID OR PREREQUISITE ID IS INVALID');
END NEW_COURSE;
I have two tables A and B .i want to copy or show the primary key column value from table A in the foreign key column in table B respectively .is there any method kindly help me.
Regards,
You can populate your primary key value while populating table B or by using a trigger when you are populating table A.
CREATE TABLE t1 (id1 NUMBER, dt DATE);
ALTER TABLE t1 ADD (
CONSTRAINT t1_pk
PRIMARY KEY
(id1));
CREATE TABLE t2 (id2 NUMBER, id1 NUMBER, dt2 DATE);
ALTER TABLE t2 ADD (
CONSTRAINT t2_pk
PRIMARY KEY
(id2));
ALTER TABLE t2
ADD CONSTRAINT t2_r01
FOREIGN KEY (id2)
REFERENCES t1 (id1);
First Approach, by this way you could populate second table when you are inserting values.
INSERT INTO t1
VALUES (1, SYSDATE
);
INSERT INTO t2
VALUES (1, 1, SYSDATE
);
With trigger, so when values are inserted into first table second tables values are populated using a trigger. So primary key value of first table is being inserted into foreign key of table 2.
CREATE OR REPLACE TRIGGER my_trigger
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2
VALUES (1, :new.id1, SYSDATE
);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20299)));
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20298)));
END;