本次实验目的是为了学习建立外键,以及利用FOREIGN KEY……REFERENCES子句以及各种约束保证参照完整性。

参照完整性原理解析:

1.参照完整性

参照完整性是指两个表的主关键字和外关键字的数据应对应一致。确保了有主关键字的表中对应其他表的外关键字的行存在,即保证了表之间的数据的一致性,防止了数据丢失或无意义的数据在数据库中扩散。参照完整性是建立在外关键字和主关键字之间或外关键字和唯一性关键字之间的关系上的。

参照完整性规则:关系R的外来码取值必须使关系S中某个元组的主码值,或者可以是一个“空值”。

定义外键时定义参照完整性,约束参照表A和被参照表B。对于违反参照完整性有时候并不是简单拒绝执行,而是接受该操作,同时执行必要的附加操作。DBMS提供机制来定义是否必须制定外键的具体值而非空值。主键和外键列可以有不同的名字,空值的要求也可以不一致,默认值也可以不同,但数据类型必须相同。


以下是本次实验的练习与习题答案:(school表在此并未发出,请参考之前的练习)

USE SCHOOL
--2.2.4实验练习
--(1)为演示参照完整性,建立表COURSE,令CNO为其主键,并在STU_UNION中插入数据。为下面的实验步骤做预先准备。
CREATE TABLE STU_UNION
(
SNO CHAR(10) NOT NULL UNIQUE,
SNAME CHAR(8),
SSEX CHAR(2),
SAGE INT,
SDEPT CHAR(20),
CONSTRAINT PK_STU_UNION PRIMARY KEY(SNO)
)
SELECT * FROM STU_UNION
DROP TABLE STU_UNION
INSERT STU_UNION VALUES('11111','郑兆涵','男','20','CS');
UPDATE STU_UNION SET SNO='' WHERE SDEPT ='CS';
INSERT STU_UNION VALUES('11112','郑兆涵1','男','20','CS');
UPDATE STU_UNION SET SNO='99999' WHERE SNAME='郑兆涵1'
INSERT STU_UNION VALUES('11111','郑兆涵','男','20','CS');
--****注1:当建立逐渐sno之后,进行一次插入信息11111,当更新之后sno变为' ',此时可以再次插入一遍11111,因为在之前建表的时候,只规定主键时sno,所以只要sno不同即可再次插入。
--****注1:将主键设为' ',并不是NULL

CREATE TABLE COURSE
(
CNO CHAR(10) NOT NULL UNIQUE,
CNAME VARCHAR(50),
CPOINTS INT
CONSTRAINT PK_COURSE PRIMARY KEY(CNO)
);
INSERT INTO COURSE VALUES('001','COMPUTERNETWORKS','2');
INSERT INTO COURSE VALUES('002','DABABASE','3');
INSERT INTO COURSE VALUES('003','CHINESE','2');
SELECT * FROM COURSE
DROP TABLE COURSE


--(2)建立表SC,令SNO和CNO分别为参照STU_UNION表以及COURSE表的外键,设定为级联删除,并令(SNO,CNO)为其主键。在不违反参照完整性的前提下,插入数据。
CREATE TABLE SC
(
SNO CHAR(10) NOT NULL,
CNO CHAR(10) NOT NULL,
GRADE SMALLINT,
PRIMARY KEY(SNO,CNO),
FOREIGN KEY(CNO) REFERENCES COURSE(CNO),
FOREIGN KEY(SNO) REFERENCES STU_UNION(SNO)
)
SELECT * FROM SC
DROP TABLE SC
INSERT INTO SC VALUES('11111','001','100')
INSERT INTO SC VALUES('11111','002','90')
INSERT INTO SC VALUES('99999','002','80')
INSERT INTO SC VALUES('99999','003','70')
INSERT INTO SC VALUES('10001','003','70')


--(3)演示违反参照完整性的插入数据。
INSERT INTO SC VALUES('11112','001','100')--主键唯一不能有重复值,所以报错


--(4)在STU_UNION中删除数据,演示级联删除。
SELECT * FROM STU_UNION
DELETE FROM STU_UNION WHERE SNO=' '
SELECT * FROM SC


--(5)在COURSE中删除数据,演示级联删除。
SELECT * FROM COURSE
DELETE FROM COURSE WHERE CPOINTS='3'
SELECT * FROM SC


--(6)为了演示级联多重级联删除,建立STU_CARD表,令STU_ID为参照STU_UNION表的外键,令CARD_ID为其主键,并插入数据。
CREATE TABLE STU_CARD
(
STU_ID CHAR(10) REFERENCES STUDENTS(SID) ON DELETE CASCADE,
CARD_ID CHAR(14),
REMAINED_MONEY DECIMAL(10,2),
CONSTRAINT PK_STU_CARD PRIMARY KEY (CARD_ID)
);
INSERT INTO STU_CARD VALUES('05212567','800001216',100.25);
INSERT INTO STU_CARD VALUES('05212222','800005753',200.50);
SELECT * FROM STU_CARD;


--(7)为演示多重级联删除,建立ICBC_CARD表,令STU_CARD_ID为参照STU_CARD表的外键,令BANK_ID为其主键,并插入数据。
CREATE TABLE ICBC_CARD
(
BANK_ID CHAR(20),
STU_CARD_ID CHAR(14) REFERENCES STU_CARD(CARD_ID) ON DELETE CASCADE,
RESTORED_MONEY DECIMAL(10,2),
CONSTRAINT PK_ICBC_CARD PRIMARY KEY(BANK_ID)
)
INSERT INTO ICBC_CARD VALUES('9558844022312','05212567',15000.1);
INSERT INTO ICBC_CARD VALUES('9558844023645','05212222',15000.3);
SELECT * FROM ICBC_CARD;


--(8)通过删除STUDENTS表中的一条记录,演示三个表的多重级联删除。
ALTER TABLE CHOICES DROP [FK_CHOICES_STUDENTS];
ALTER TABLE CHOICES ADD
CONSTRAINT [FK_CHOICES_STUDENTS] FOREIGN KEY
(
	[SID]
) REFERENCES [dbo].[STUDENTS]
	(
		[SID]
	) ON DELETE CASCADE;
DELETE FROM STUDENTS WHERE SID='800001216';
SELECT * FROM STU_CARD;
SELECT * FROM ICBC_CARD;
--*****注:由于数据库中原有表choices使用了外键关联students表,采用了no action,其外键又限定非空,所以直接在students中删除数据会出错。要演示多重级联删除必须取出原有约束,并将其外键设置为级联删除。
ALTER TABLE ICBC_CARD
DROP CONSTRAINT FK__ICBC_CARD__STU_C__6c190EBB;
ALTER TABLE ICBC_CARD
ADD CONSTRAINT FK_ICBC_CARD FOREIGN KEY(STU_CARD_ID)
	REFERENCES STU_CARD(CARD_ID) ON DELETE NO ACTION;
--*****注:FK__ICBC_CARD__STU_C__6c190EBB是原有外键的约束名称,可通过MANAGERMENT STUDIO窗口左部的对象浏览器选取指定的表,展开目录后可以看到“约束”项,从哪里可以查到约束的名称。
BEGIN TRANSACTION DEL
DELETE FROM STUDENTS WHERE SID='800005753';
SELECT * FROM STU_CARD;
SELECT * FROM ICBC_CARD;
COMMIT TRANSACTION DEL
--****注:事务DEL由于ICBC_CARD表中的外键属性使ON DELETE NO ACTION,所以多重级联删除倒了ICBC_CARD无法执行,于是整个事务回滚。


--(9)演示事务中进行多重级联删除失败的处理。修改ICBC_CARD表的外键属性,使其变为ON DELETE NO ACTION ,演示事务中通过删除STUDENTS表中的一条记录,多重级联删除失败,整个事务回滚到事务的初始状态。
ALTER TABLE ICBC_CARD
DROP CONSTRAINT FK__ICBC_CARD__STU_C__6c190EBB;
ALTER TABLE ICBC_CARD
ADD CONSTRAINT FK_ICBC_CARD FOREIGN KEY(STU_CARD_ID)
	REFERENCES STU_CARD(CARD_ID) ON DELETE NO ACTION;
--*****注:FK__ICBC_CARD__STU_C__6c190EBB是原有外键的约束名称,可通过MANAGERMENT STUDIO窗口左部的对象浏览器选取指定的表,展开目录后可以看到“约束”项,从哪里可以查到约束的名称。
BEGIN TRANSACTION DEL
DELETE FROM STUDENTS WHERE SID='800005753';
SELECT * FROM STU_CARD;
SELECT * FROM ICBC_CARD;
COMMIT TRANSACTION DEL
--****注:事务DEL由于ICBC_CARD表中的外键属性使ON DELETE NO ACTION,所以多重级联删除倒了ICBC_CARD无法执行,于是整个事务回滚。


--(10)演示互参照问题及其解决方法。要建立教师授课和课程制定教师听课关系的两张表,规定一个教师可以授多门课,但是每个课程只能制定一个教师去听课,所以要为两张表建立互相之间的参照关系。
CREATE TABLE LISTEN_COURSE
(
TEACHER_ID CHAR(6),
TNAME VARCHAR(20),
COURSE_ID CHAR(4)
CONSTRAINT PK_LISTEN_COURSE PRIMARY KEY(TEACHER_ID)
)
CREATE TABLE TEACH_COURSE
(
COURSE_ID CHAR(4),
CNAME VARCHAR(30),
TEACHER_ID CHAR(6)
CONSTRAINT PK_TEACH_COURSE PRIMARY KEY(COURSE_ID)
CONSTRAINT FK_TEACH_COURSE FOREIGN KEY(TEACHER_ID)
	REFERENCES LISTEN_COURSE(TEACHER_ID)
)
ALTER TABLE LISTEN_COURSE
	ADD CONSTRAINT FK_LISTEN_COURSE FOREIGN KEY(COURSE_ID)
		REFERENCES TEACH_COURSE(COURSE_ID)



运行结果请读者自试。