如何使用两个属性对外键施加约束?
How can I put constraint to a foreign key using two attributes?
有两个表Staff
和Patient
。
Staff
有几列,其中两列是 Staff_ID
和 Category
。
Patient
也有一些与 his/her 约会相关的列,其中两个是 Nurse_ID
和 Doc_ID
并且它们都是外键引用 Staff_ID
.
A Staff_ID
是 Doc_ID
if Category='Doctor'
并且它是 Nurse_ID
if Category='Nurse'
.
create table Staff
(
Staff_ID varchar2(7) check (Staff_ID like 'SF%') primary key,
Staff_Name varchar2(20),
Category varchar2(20) check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor'),
Designation varchar2(20) check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor'),
DOB date,
Contact integer(10),
Address varchar2(50),
Dept_No varchar2(7) foreign key references Department(Dept_No)
);
create table Patient
(
Pat_ID varchar2(7) check (Pat_ID like 'P%') primary key,
Doc_ID varchar2(7) foreign key references Staff(Staff_ID) check (Category='Doctor'),
Nurse_ID varchar2(7) foreign key references Staff(Staff_ID) check (Category='Nurse'),
Consult_Room_No integer(4),
Date_Of_Appointment date,
Time_Of_Appointment time
);
如何为 2 个不同的列创建相同的外键?
您的脚本中有几处错误:
- 缺少右括号
- 错误的数据类型(Oracle 中没有
time
数据类型)
- 您可以用两个外键引用一个主键,但它们必须相互独立。
- 您可以检查 patient 中的类别,因为该字段不是 table 的一部分。但是,您可以使用触发器来做到这一点。
- 虽然我没有更改下面示例中的定义,但您应该考虑为那些需要这种行为的字段(所有属于任何类型约束的字段)添加 NOT NULL 约束
改用这个(出于示例的目的,我使用 alter table add constraint
作为语句而不是将所有内容都放在 create table
语句中)
create table Department ( dept_no varchar2(7) ) ;
alter table department add primary key ( dept_no ) ;
create table Staff
(
Staff_ID varchar2(7) primary key ,
Staff_Name varchar2(20) ,
Category varchar2(20) ,
Designation varchar2(20) ,
DOB date ,
Contact number(10) ,
Address varchar2(50) ,
dept_no varchar2(7)
);
alter table staff add constraint fk_stf_on_dpt FOREIGN KEY (dept_no) references Department(dept_no) ;
alter table staff add constraint chk_stf_id check (Staff_ID like 'SF%'),
alter table staff add constraint chk_des_na check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor') ) ;
alter table staff add constraint chk_cat_na check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor') ) ;
create table Patient
(
Pat_ID varchar2(7) ,
Doc_ID varchar2(7) ,
Nurse_ID varchar2(7) ,
Consult_Room_No number(4),
Date_Of_Appointment date,
Time_Of_Appointment date
);
alter table Patient add primary key ( Pat_ID ) ;
alter table patient add constraint chk_nur_id check ( nurse_id in ( 'Nurse' ) );
alter table Patient add constraint fk_pat_id foreign key (Doc_ID) references staff(staff_id) ;
alter table Patient add constraint fk_nur_id foreign key (Nurse_Id) references staff(staff_id) ;
测试运行
SQL> @ddl.sql
SQL> create table Department ( dept_no varchar2(7) ) ;
Table created.
SQL>
SQL> alter table department add primary key ( dept_no ) ;
Table altered.
SQL>
SQL> create table Staff
2 (
3 Staff_ID varchar2(7) primary key ,
4 Staff_Name varchar2(20) ,
5 Category varchar2(20) ,
6 Designation varchar2(20) ,
7 DOB date ,
8 Contact number(10) ,
9 Address varchar2(50) ,
10 dept_no varchar2(7)
11 );
Table created.
SQL>
SQL> alter table staff add constraint fk_stf_on_dpt FOREIGN KEY (dept_no) references Department(dept_no) ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_stf_id check (Staff_ID like 'SF%') ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_des_na check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor') ) ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_cat_na check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor') ) ;
Table altered.
SQL>
SQL>
SQL> create table Patient
2 (
3 Pat_ID varchar2(7) ,
4 Doc_ID varchar2(7) ,
5 Nurse_ID varchar2(7) ,
6 Consult_Room_No number(4),
7 Date_Of_Appointment date,
8 Time_Of_Appointment date
9 );
Table created.
SQL>
SQL> alter table Patient add primary key ( Pat_ID ) ;
Table altered.
SQL>
SQL> alter table Patient add constraint chk_pat_id check (Pat_ID like 'P%') ;
Table altered.
SQL>
SQL> alter table Patient add constraint fk_pat_id foreign key (Doc_ID) references staff(staff_id) ;
Table altered.
SQL>
SQL> alter table Patient add constraint fk_nur_id foreign key (Nurse_Id) references staff(staff_id) ;
Table altered.
SQL>
SQL> insert into Department values ( 'SF100' ) ;
1 row created.
SQL> insert into Staff ( Staff_ID , dept_no ) values ( 'SF1001' , 'SF100' ) ;
1 row created.
SQL> insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' ) ;
insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' )
*
ERROR at line 1:
ORA-02291: integrity constraint (TEST_PERF.FK_NUR_ID) violated - parent key not
found
SQL> insert into Staff ( Staff_ID , dept_no ) values ( 'SF1002' , 'SF100' ) ;
1 row created.
SQL> insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' ) ;
1 row created.
SQL> insert into Staff ( staff_id , dept_no ) values ( 'SR10003' , 'SR103' ) ;
insert into Staff ( staff_id , dept_no ) values ( 'SR10003' , 'SR103' )
*
ERROR at line 1:
ORA-02290: check constraint (TEST_PERF.CHK_STF_ID) violated
SQL> insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Head Nurse' ) ;
insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Head Nurse' )
*
ERROR at line 1:
ORA-02290: check constraint (TEST_PERF.CHK_CAT_NA) violated
SQL> insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Nurse' ) ;
1 row created.
SQL>
然后添加此触发器以根据类别控制 staff_id 的行为(您可以按照自己的方式重写触发器)
create trigger t_patient before insert or update on patient
for each row
declare
vcategory_nurse pls_integer;
vcategory_docid pls_integer;
begin
if inserting or updating
then
select count(category) into vcategory_nurse from staff where staff_id = :new.doc_id and category = 'Nurse';
select count(category) into vcategory_docid from staff where staff_id = :new.nurse_id and category = 'Doctor';
if vcategory_nurse != 0
then
raise_application_error(-20001,'Staff Id is Doctor not Nurse');
end if;
if vcategory_docid != 0
then
raise_application_error(-20001,'Staff Id is Nurse not Doctor');
end if;
end if;
end;
/
触发器的测试用例
SQL> insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1001' ) ;
insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1001' )
*
ERROR at line 1:
ORA-20001: Staff Id is Nurse not Doctor
ORA-06512: at "TEST_PERF.T_PATIENT", line 15
ORA-04088: error during execution of trigger 'TEST_PERF.T_PATIENT'
SQL> insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1004' ) ;
1 row created.
SQL> select staff_id , category from staff ;
STAFF_I CATEGORY
------- --------------------
SF1001 Doctor
SF1002
SF1003
SF1004 Nurse
有两个表Staff
和Patient
。
Staff
有几列,其中两列是 Staff_ID
和 Category
。
Patient
也有一些与 his/her 约会相关的列,其中两个是 Nurse_ID
和 Doc_ID
并且它们都是外键引用 Staff_ID
.
A Staff_ID
是 Doc_ID
if Category='Doctor'
并且它是 Nurse_ID
if Category='Nurse'
.
create table Staff
(
Staff_ID varchar2(7) check (Staff_ID like 'SF%') primary key,
Staff_Name varchar2(20),
Category varchar2(20) check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor'),
Designation varchar2(20) check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor'),
DOB date,
Contact integer(10),
Address varchar2(50),
Dept_No varchar2(7) foreign key references Department(Dept_No)
);
create table Patient
(
Pat_ID varchar2(7) check (Pat_ID like 'P%') primary key,
Doc_ID varchar2(7) foreign key references Staff(Staff_ID) check (Category='Doctor'),
Nurse_ID varchar2(7) foreign key references Staff(Staff_ID) check (Category='Nurse'),
Consult_Room_No integer(4),
Date_Of_Appointment date,
Time_Of_Appointment time
);
如何为 2 个不同的列创建相同的外键?
您的脚本中有几处错误:
- 缺少右括号
- 错误的数据类型(Oracle 中没有
time
数据类型) - 您可以用两个外键引用一个主键,但它们必须相互独立。
- 您可以检查 patient 中的类别,因为该字段不是 table 的一部分。但是,您可以使用触发器来做到这一点。
- 虽然我没有更改下面示例中的定义,但您应该考虑为那些需要这种行为的字段(所有属于任何类型约束的字段)添加 NOT NULL 约束
改用这个(出于示例的目的,我使用 alter table add constraint
作为语句而不是将所有内容都放在 create table
语句中)
create table Department ( dept_no varchar2(7) ) ;
alter table department add primary key ( dept_no ) ;
create table Staff
(
Staff_ID varchar2(7) primary key ,
Staff_Name varchar2(20) ,
Category varchar2(20) ,
Designation varchar2(20) ,
DOB date ,
Contact number(10) ,
Address varchar2(50) ,
dept_no varchar2(7)
);
alter table staff add constraint fk_stf_on_dpt FOREIGN KEY (dept_no) references Department(dept_no) ;
alter table staff add constraint chk_stf_id check (Staff_ID like 'SF%'),
alter table staff add constraint chk_des_na check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor') ) ;
alter table staff add constraint chk_cat_na check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor') ) ;
create table Patient
(
Pat_ID varchar2(7) ,
Doc_ID varchar2(7) ,
Nurse_ID varchar2(7) ,
Consult_Room_No number(4),
Date_Of_Appointment date,
Time_Of_Appointment date
);
alter table Patient add primary key ( Pat_ID ) ;
alter table patient add constraint chk_nur_id check ( nurse_id in ( 'Nurse' ) );
alter table Patient add constraint fk_pat_id foreign key (Doc_ID) references staff(staff_id) ;
alter table Patient add constraint fk_nur_id foreign key (Nurse_Id) references staff(staff_id) ;
测试运行
SQL> @ddl.sql
SQL> create table Department ( dept_no varchar2(7) ) ;
Table created.
SQL>
SQL> alter table department add primary key ( dept_no ) ;
Table altered.
SQL>
SQL> create table Staff
2 (
3 Staff_ID varchar2(7) primary key ,
4 Staff_Name varchar2(20) ,
5 Category varchar2(20) ,
6 Designation varchar2(20) ,
7 DOB date ,
8 Contact number(10) ,
9 Address varchar2(50) ,
10 dept_no varchar2(7)
11 );
Table created.
SQL>
SQL> alter table staff add constraint fk_stf_on_dpt FOREIGN KEY (dept_no) references Department(dept_no) ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_stf_id check (Staff_ID like 'SF%') ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_des_na check (Designation in ('Staff Nurse', 'Head Nurse', 'Technician', 'Senior Technician', 'Junior Attender', 'Senior Attender', 'Junior Doctor', 'Senior Doctor') ) ;
Table altered.
SQL>
SQL> alter table staff add constraint chk_cat_na check (Category in ('Nurse', 'Lab Technician', 'Helper', 'Attender', 'Doctor') ) ;
Table altered.
SQL>
SQL>
SQL> create table Patient
2 (
3 Pat_ID varchar2(7) ,
4 Doc_ID varchar2(7) ,
5 Nurse_ID varchar2(7) ,
6 Consult_Room_No number(4),
7 Date_Of_Appointment date,
8 Time_Of_Appointment date
9 );
Table created.
SQL>
SQL> alter table Patient add primary key ( Pat_ID ) ;
Table altered.
SQL>
SQL> alter table Patient add constraint chk_pat_id check (Pat_ID like 'P%') ;
Table altered.
SQL>
SQL> alter table Patient add constraint fk_pat_id foreign key (Doc_ID) references staff(staff_id) ;
Table altered.
SQL>
SQL> alter table Patient add constraint fk_nur_id foreign key (Nurse_Id) references staff(staff_id) ;
Table altered.
SQL>
SQL> insert into Department values ( 'SF100' ) ;
1 row created.
SQL> insert into Staff ( Staff_ID , dept_no ) values ( 'SF1001' , 'SF100' ) ;
1 row created.
SQL> insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' ) ;
insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' )
*
ERROR at line 1:
ORA-02291: integrity constraint (TEST_PERF.FK_NUR_ID) violated - parent key not
found
SQL> insert into Staff ( Staff_ID , dept_no ) values ( 'SF1002' , 'SF100' ) ;
1 row created.
SQL> insert into Patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P1000' , 'SF1001' , 'SF1002' ) ;
1 row created.
SQL> insert into Staff ( staff_id , dept_no ) values ( 'SR10003' , 'SR103' ) ;
insert into Staff ( staff_id , dept_no ) values ( 'SR10003' , 'SR103' )
*
ERROR at line 1:
ORA-02290: check constraint (TEST_PERF.CHK_STF_ID) violated
SQL> insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Head Nurse' ) ;
insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Head Nurse' )
*
ERROR at line 1:
ORA-02290: check constraint (TEST_PERF.CHK_CAT_NA) violated
SQL> insert into staff ( staff_id , dept_no , category ) values ( 'SF1004' , 'SR103' , 'Nurse' ) ;
1 row created.
SQL>
然后添加此触发器以根据类别控制 staff_id 的行为(您可以按照自己的方式重写触发器)
create trigger t_patient before insert or update on patient
for each row
declare
vcategory_nurse pls_integer;
vcategory_docid pls_integer;
begin
if inserting or updating
then
select count(category) into vcategory_nurse from staff where staff_id = :new.doc_id and category = 'Nurse';
select count(category) into vcategory_docid from staff where staff_id = :new.nurse_id and category = 'Doctor';
if vcategory_nurse != 0
then
raise_application_error(-20001,'Staff Id is Doctor not Nurse');
end if;
if vcategory_docid != 0
then
raise_application_error(-20001,'Staff Id is Nurse not Doctor');
end if;
end if;
end;
/
触发器的测试用例
SQL> insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1001' ) ;
insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1001' )
*
ERROR at line 1:
ORA-20001: Staff Id is Nurse not Doctor
ORA-06512: at "TEST_PERF.T_PATIENT", line 15
ORA-04088: error during execution of trigger 'TEST_PERF.T_PATIENT'
SQL> insert into patient ( Pat_ID , Doc_ID , Nurse_ID ) values ( 'P10005' , 'SF1001' , 'SF1004' ) ;
1 row created.
SQL> select staff_id , category from staff ;
STAFF_I CATEGORY
------- --------------------
SF1001 Doctor
SF1002
SF1003
SF1004 Nurse