第五章完整性

一,实体完整性

这里是引用

【例5.1】将Student表中的Sno属性定义为码

CREATE TABLE Student
(
	Sno CHAR(9)PRIMARY,--在列级定义主码
	Sname CHAR(20) NOT NULL,
	Ssex CHAR(2),
	Sage SMALLINT
	Sdept CHAR(20)
);
--OR
CREATE TABLE Student
(
	Sno CHAR(9)PRIMARY,
	Sname CHAR(20) NOT NULL,
	Ssex CHAR(2),
	Sage SMALLINT
	Sdept CHAR(20),
	PRIMARY KEY(Sno)--在表级定义主码
);

【5.2】将SC表中的Sno,Cno属性组定义为码

CREATE TABLE SC
(
	Sno CHAR(9) NOT NULL,
	Cno CHAR(4) NOT NULL,
	Grade SMALLINT,
	PRIMARY KEY(Sno,Cno)
);

二,参照完整性

这里是引用

[例5.3]定义SC中的参照完整性

CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
 Cno CAHR(4) NOT NULL,
 Grade SMALLINT,
 PRIMARY KEY(Sno,Cno),--在表级定义实体完整性
 FOREIGN KEY REFERENCES Student(Sno),--在表级定义参照完整性
 FOREIGN KEY REFERENCES Course(Cno)--在表级定义参照完整性
);

在这里插入图片描述

[例5.4] 显式说明参照完整性的违约处理示例

CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
 Cno CHAR(2) NOT NULL,
 Grade SMALLINT,
 PRIMARY KEY(Sno,Cno),
 FOREIGN KEY(Sno) REFERENCES Student(Sno)
  ON DELETE CASCADE --级联删除SC表中相应的元组
  ON UPDATE CASCADE --级联更新SC表中相应的元组
 FOREIGN KEY(Cno) REFERENCES Course(Cno)
  ON DELETE ON ACTION --当删除course 表中的元组造成了与SC表不一致时拒绝删除
  ON UPDATE CASCADE --当更新course表中的cno时,级联更新SC表中相应的元组
);

三,用户定义的完整性

1.属性上的约束条件

针对某一具体应用的数据必须满足的语义要求
CREATE TABLE时定义属性上的约束条件
列值非空(NOT NULL)
列值唯一(UNIQUE)
检查列值是否满足一个条件表达式(CHECK)

(1)不允许取空值

[例5.5] 在定义SC表时,说明Sno、Cno、Grade属性不允许取空值。

CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT NOT NULL,
PRIMARY KEY (Sno,Cno)
);

(2)列值唯一

[例5.6]建立部门表DEPT,要求部门名称Dname列取值唯一,部门编号Deptno列为主码

CREATE TABLE DEPT
(Deptno NUMERIC(2),
 Dname CHAR(9) UNIQUE NOT NULL --要求Dname列值唯一, 并且不能取空值
 Location CHAR(10),
 PRIMARY KEY(Deptno)
);

(3)用CHECK短语指定列值应该满足的条件

[例5.7] Student表的Ssex只允许取“男”或“女”。

CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY,
 Sname CHAR(8) NOT NULL,
 Ssex CHAR(2) CHECK (Ssex IN('男','女'))
 Sage SMALLINT,
 Sdept CHAR(20)
);

[例5.8] SC表的Grade的值应该在0和100之间。

CREATE TABLE SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT CHECK (Grade>=0 AND Grade<=100),--Grade取值范围是0到100
PRIMARY KEY(Sno,Cno), 
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(Cno) REFERENCES Course(Cno)
);

2.元组上的约束条件

在CREATE TABLE时可以用CHECK短语定义元组上的约束条件,即元组级的限制

[例5.9]当学生的性别是男时,其名字不能以Ms.打头。

CREATE TABLE Student
(Sno CHAR(9),
 Sname CHAR(8) NOT NULL,
 Ssex CHAR(2),
 Sage SMALLINT,
 Sdept CHAR(20),
 PRIMARY KEY(Sno),
 CHECK (Ssex='女' OR Sname NOT LIKE 'Ms.%')
 --定义了元组中Sname和 Ssex两个属性值之间的约束条件
);
  • 性别是女性的元组都能通过该项检查,因为Ssex=‘女’成立;
  • 当性别是男性时,要通过检查则名字一定不能以Ms.打头

四,完整性约束命名字句

1.完整性约束命名子句

CONSTRAINT <完整性约束条件名><完整性约束条件>

<完整性约束条件>包括NOT NULL、UNIQUE、PRIMARY KEY短语、FOREIGN KEY短语、CHECK短语等

[例5.10]建立学生登记表Student,要求学号在90000~99999之间,姓名不能取空值,年龄小于30,性别只能是“男”或“女”。

CREATE TABLE Student
(Sno NUMERIC(6)
 CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999),
 Sname CHAR(9)
 CONSTRAINT C2 NOT NULL,
 Sage NUMERIC(3)
 CONSTRAINT C3 CHECK(Sage<30),
 Sex CHAR(2)
 CONSTRAINT C4 CHECK (Ssex IN ('男','女')),
 CONSTRAINT Studentkey PRIMARY KEY(Sno)
);

在Student表上建立了5个约束条件,包括主码约束(命名为StudentKey)以及C1、C2、C3、C4四个列级约束。

[例5.11]建立教师表TEACHER,要求每个教师的应发工资不低于3000元。应发工资是工资列Sal与扣除项Deduct之和。

CREATE TABLE Teacher
(Eno NUMERIC(4) PRIMARY KEY
 Ename CHAR(10),
 Job CHAR(8),
 Sal NUMERIC(7,2),
 Deduct NUMERIC(7,2),
 Deptno NUMERIC(2),
 CONSTRAINT TEACHERFKey FOREIGN KEY (Deptno) REFERENCES DEPT(Deptno),
 CONSTRAINT C1 CHECK (Sal + Deduct >= 3000) 
);

2.修改表中的完整性限制

[例5.12]去掉例5.10 Student表中对性别的限制。

ALTER TABLE Student
DROP CONSTRAINT C4;

[例5.13] 修改表Student中的约束条件,要求学号改为在900000~999999之间,年龄由小于30改为小于40

ALTER TABLE Student
DROP CONSTRAINT C1;
ALTER TABLE Student
ADD CONSTRAINT C1 CHECK(Sno BETWEEN 900000 AND 999999),
ALTER TABLE Student 
DROP CONSTRAINT C3;
ALTER TABLE Student
ADD CONSTRAINT C3 CHECK(Sage<40);

五,断言

在这里插入图片描述

1.创建断言的语句格式

CREATE ASSERTION<断言名><CHECK 子句> 每个断言都被赋予一个名字,<CHECK
子句>中的约束条件与WHERE子句的条件表达式类似。

只有标准SQL语句
[例5.18] 限制数据库课程最多60名学生选修

CREATE ASSERTION ASS_SC_CNUM1
CHECK (60>=ALL(SELECT COUNT(*))
			   FROM Course,SC 
			   WHERE SC.Cno=Course.Cno AND Course.Cname='数据库');

[例5.19]限制每一门课程最多60名学生选修

CREATE ASSERTION ASSE_SC_CNUM1
	CHECK(60>=ALL(SELECT COUNT(*)
				  FROM SC
				  GROUP BY Cno)
		  );
/*此断言的谓词,涉及聚集操作count 和分组函数group by的SQL语句*/

2.删除断言的语句格式为

DROP ASSERTION <断言名>;

在这里插入图片描述

六,触发器(Trigger)

功能介绍

1.任何用户对表的增、删、改操作均由服务器自动激活相应的触发器
2.触发器可以实施更为复杂的检查和操作,具有更精细和更强大的数据控制能力

1.定义触发器

CREATE TRIGGER语法格式:
CREATE TRIGGER <触发器名>
{BEFORE | AFTER} <触发事件> ON <表名>
REFERENCING NEW|OLD ROW AS<变量>
FOR EACH {ROW | STATEMENT}
[WHEN <触发条件>]<触发动作体>

2.触发事件

触发事件可以是INSERT、DELETE或UPDATE也可以是这几个事件的组合
还可以UPDATE OF<触发列,…>,即进一步指明修改哪些列时激活触发器
AFTER/BEFORE是触发的时机
AFTER表示在触发事件的操作执行之后激活触发器
BEFORE表示在触发事件的操作执行之前激活触发器

3.触发器类型

行级触发器(FOR EACH ROW)
语句级触发器(FOR EACH STATEMENT)

例如,在例5.11的TEACHER表上创建一个AFTER UPDATE触发器,触发事件是UPDATE语句:
UPDATE TEACHER SET Deptno=5;
假设表TEACHER有1000行
如果是语句级触发器,那么执行完该语句后,触发动作只发生1次
如果是行级触发器,触发动作将执行1000次

不同的RDBMS产品触发器语法各不相同

[例5.21]当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中:

SQL

CREATE TRIGGER SC_T
AFTER UPDATE OF Grade ON SC
REFERENCING
	OLD row AS OldTuple
	NEW row AS NewTuple --REFERENCING指出引用变量,但是T-SQL并不支持
FOR EACH ROW
WHEN (NewTuple.Grade>=1.1*OldTuple.Grade)
	INSERT INTO SC_U(SNO,Cno,OldGrade,NewGrade)
	VALUES(OldTuple.Sno,OldTuple.Cno,OldTuple.Grade,NewTuple.Grade)

T-SQL

CREATE TRIGGER SC_T
ON SC
AFTER UPDATE
AS
BEGIN
DECLARE @Sno CHAR(9),@Cno CHAR(4),@OLDGRADE SMALLINT,@NEWGRADE SMALLINT
SELECT @Sno=Sno FROM INSERTED
SELECT @Cno=Cno FROM INSERTED
SELECT @OLDGRADE=GRADE FROM DELETED
SELECT @NEWGRADE=GRADE FROM INSERTED
IF(@NEWGRADE>=1.1*@OLDGRADE)
BEGIN
INSERT INTO SC_U
VALUES(@Sno,@Cno,@OLDGRADE,@NEWGRADE)
END;
END;

[例5.22] 将每次对表Student的插入操作所增加的学生个数记录到表StudentInsertLog中。

SQL

CREATE TRIGGER Student_CNT
AFTER INSERT ON Student
REFERENCING 
NEW TABLE AS DELTA
FOR EACH STATEMENT
INSERT INTO Student StudentINSERTLOG(NUMBERS)
SELECT CNT(*)FROM DELTA

T-SQL

CREATE TRIGGER Student_Count
ON Student 
AFTER INSERT
AS
INSERT 
INTO StudentInsertLog(Number)
SELECT COUNT(*) FROM Student;

[例5.23] 定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。

SQL

CREATE TRIGGER INSERT_OR_UPDATE_SAL  --对教师表插入或更新时激活触发器
BEFORE INSERT OR UPDATE ON TEACHER    --before 触发事件
REFERENCING NEW ROW AS NEWTUPLE      
FOR EACH ROW             --行触发器
BEGIN                         --定义触发动作体,这是一个PL/SQL过程块
IF(NEWTUPLE.Job='教授')AND (NEWTUPLE.SAL<4000)
THEN NEWTUPLE.SAL:=4000;   --因为是行触发器,可在过程体中
END IF;
END;                       --触发动作结束

T-SQL

CREATE TRIGGER Insert_or_Update_Sal
ON Teacher 
FOR INSERT,UPDATE 
AS
DECLARE @Newtuple INT
DECLARE @Job CHAR(10)
IF (UPDATE(Salary))
SELECT @Salary=Salary FROM INSERTED
SELECT @Job=Job FROM Teacher
IF(@Job='教授')AND(@Salary<4000)
UPDATE Teacher
SET Salary=4000
WHERE Job='教授'AND Salary<4000;

删除触发器

触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除

DROP TRIGGER <触发器>ON<表名>

七,存储过程

1.创建存储过程

CREATE OR REPLACE PROCEDURE 过程名([参数1,参数2,...]) AS <过程化SQL>

[例8.8] 利用存储过程来实现下面的应用:从账户1转指定数额的款项到账户2中。

SQL

CREATE OR REPLACE PROCEDURE TRANSFER
(INACCOUNT INT,OUTACCOUNT INT,AMOUNT FLOAT)
AS DECLARE
TOTALDEPOSITOUT FLOAT;
TOTALDEPOSITIN FLOAT;
INACCOUNTNUM INT;
BEGIN
SELECT TOTAL INTO TOTALDEPOSITOUT
FROM ACCOUNT 
WHERE ACCOUNTNUM=OUTACCOUNT;
IF TOTALDEPOSITOUT IS NULL THEN
ROLLBACK;
RETURN;
END IF;
IF TOTALDEPOSITOUT<AMOUNT THEN
ROLLBACK;
RETURN;
END IF;
SELECT ACCOUNTNUM INTO INACCOUNTNUM 
FROM ACCOUNT
WHERE ACCOUNTNUM=IN ACCOUNT;
IF INACCOUNT IS NULL THEN
ROLLBACK;
RETURN;
END IF;
UPDATE ACCOUNT SET TOTAL=TATAL-AMOUNT WHERE ACCOUNTNUM=OUTACCOUNT;
UPDATE ACCOUNT SET TOTAL=TATAL+AMOUNT WHERE ACCOUNTNUM=INACCOUNT;
COMMIT;
END;

T-SQL

IF(EXISTS(SELECT * FROM SYS.OBJECTS WHERE NAME='P_T'))
DROP PROCEDURE P_T
GO
CREATE PROCEDURE P_T
@INID CHAR(3),@OUTID CHAR(3),@AMOUNT FLOAT
AS
BEGIN
TRANSACTION TRANS
DECLARE @TOTALOUT FLOAT,@TOTALIN FLOAT,@OUTIDNUM CHAR(3);   --查询转出账户余额
SELECT @TOTALOUT=TOTAL FROM T_RE WHERE ANUM=@OUTID;
IF(@TOTALOUT IS NULL) BEGIN PRINT'账户不存在或者无余额'
ROLLBACK TRANSACTION TRANS;RETURN ; END; --回滚事务
IF(@TOTALOUT<@AMOUNT)BEGIN PRINT'账户余额不足' 
ROLLBACK TRANSACTION TRANS;RETURN;END;
SELECT @TOTALIN=ANUM FROM T_RE WHERE ANUM=@INID;
IF(@TOTALIN IS NULL) BEGIN PRINT'转入账户不存在'
ROLLBACK TRANSACTION TRANS;RETURN;END;
BEGIN
UPDATE T_RE SET TOTAL=TOTAL-@AMOUNT WHERE ANUM=@OUTID;
UPDATE T_RE SET TOTAL=TOTAL+@AMOUNT WHERE ANUM=@INID;
PRINT'请取走银行卡'
COMMIT TRANSACTION TRANS;
RETURN;
END;

转账

SELECT * FROM T_RE;
EXEC	P_T
		@INID = 101,	--转入账户
		@OUTID = 102,	--转出账户
		@amount = 50		--转出金额

SELECT * FROM T_RE;

2.执行存储过程

CALL/PERFORM PROCEDURE 过程名([参数1,参数2,...]);

[例8.10]从账户01转100元到02账户中

CALL PROCEDURE TRANSFER (01,02,100);

3.修改存储过程

使用ALTER PROCEDURE 重命名一个存储过程

ALTER PROCEDURE 过程1 RENAME TO 过程2

4.删除存储过程

DROP PROCEDURE 过程名();

八,函数

1、函数的定义语句格式。

CREATE OR REPLACE FUNCTION 函数名 ([参数1,参数2,...])RETURNS<类型>
AS <过程化SQL>;

2、函数的执行语句格式。

CALL/SELECT 函数名 ([参数1,参数2,...]);

3、修改函数。

重命名一个自定义函数

ALTER FUNCTION 过程名1 RENAME TO 过程名2

重新编译一个函数

ALTER FUNCTION 函数名 COMPILE;
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值