【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION

数据库完整性

数据库完整性是指数据的正确性和相容性。
数据的正确性:符合现实世界语义
数据的相容性:同一对象在不同关系中的数据是符合逻辑的
数据的完整性:防范对象:不合语义的、不正确的数据
数据的安全性:防范对象:非法用户和非法操作

实体完整性
CREATE TABLE中用PRIMAY KEY来定义为主码
检查主码值是否唯一 检查主码的各个属性是否为空
例5.1
将Student表中的Sno属性定义为码。

CREATE TABLE Student
(
Sno CHAR(9) PRIMARY KEY,
Sname CHAR(20) NOT NULL,
Ssex SMALLINT,
Sdept CHAR(20)
);

或者最后定义主码:

CREATE TABLE Student
(
Sno CHAR(9),
Sname CHAR(20) NOT NULL,
Ssex SMALLINT,
Sdept CHAR(20),
 PRIMARY KEY(Sno)
);

例5.2
将SC表中的Sno,Cno属性定义为码。

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

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第1张图片检查:
1、检查主码是否唯一,如果不唯一则拒绝插入或修改。
2、检查主码的各个属性是否为空,只要有一个为空就拒绝或修改。

参照完整性
CREATE TABLE中用FOREIGN KEY短语定义为外码,还应该定义外码列是否允许为空值。
FOREIGN KEY(Sno) REFERENCES Student(Sno)在表级定义参照完整性
主码不能设为空值,外码可以
例5.3
定义SC中的参照完整性

CREATE TABLE SC
(
Sno CHAR(9) NOT NULL,
Cno CHAR(9) NOT NULL,
Grade SMALLINT,
PRIMARY KEY(Sno,Cno)
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(CNO) REFERENCES Course(Cno)
);

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第2张图片处理策略:
1、拒绝执行(默认策略)
2、级联操作
3、设置为空值
例5.4
显示说明参照完整性的违约处理实例。

CREATE TABLE SC
(
Sno CHAR(9),
Cno CHAR(9),
Grade SMALLINT,
PRIMARY KEY(Sno,Cno)
FOREIGN KEY(Sno) REFERENCES Student(Sno)
         ON DELETE CASCADE
		 ON UPDATE CASCADE,
FOREIGN KEY(CNO) REFERENCES Course(Cno)
        ON DELETE NO ACTION
		ON UPDATE CASCADE
);

显示说明 ON DELETE CASCADE级联删除
ON DELETE NO ACTION 拒绝删除
ON UPDATE CASCADE 级联更新

用户定义的完整性
针对某一具体应用的数据必须满足的语义要求
属性上的:NOT NULL(列值非空)、UNIQUE(列值唯一)、CHECK(检查列值是否满足一个条件)
例:CHECK (Ssex IN (‘男’,’女’))

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

CREATE TABLE SC
(
Sno CHAR(9) NOT NULL,
Cno CHAR(9) NOT NULL,
Grade SMALLINT NOT NULL,
PRIMARY KEY(Sno,Cno)
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(CNO) REFERENCES Course(Cno)
);

2、列值唯一
例5.6
建立部门表DEPT,要求部门名称Dname列值唯一,部门编码Deptno列为主码。

CREATE TABLE DEPT
(
Deptno NUMERIC(2),
Dname CHAR(9) UNIQUE NOT NULL,
Dlocation CHAR(10),
PRIMARY KEY(Deptno)
);

3、用CHECK短语指定列值应该满足的条件
例5.7
Student表的Ssex只允许取“男”或“女”。

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

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

在这里插入代码片
CREATE TABLE SC
(
Sno CHAR(9),
Cno CHAR(9),
Grade SMALLINT CHECK(Grade>=0 AND Grade <=100),
PRIMARY KEY(Sno,Cno)
FOREIGN KEY(Sno) REFERENCES Student(Sno),
FOREIGN KEY(CNO) REFERENCES Course(Cno)
);

元组上的约束条件
在CREATE TABLE语句中可以用CHECK短语定义元组上的约束条件,即元组级的限制。
例5.9
当学生的性别是男时,其名字不能以Ms.打头。

CREATE TABLE Stuent
(
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.%')
);

完整性约束命名子句
完整性约束命名子句

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

完整性约束条件包括NOT NULL,UNIQUE,PRIMARY,FOREIGN KEY,CHECK短语等。
名字用到就起名,用不到系统也会自定义
例5.10
建立学生登记表Student,要求学号在90000~99999之间,姓名不能取空值,年龄小于30,性别只能是“男”或“女”。

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

例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)
);

Numeric(7,2)表示总位数为7,小数点后为2位的数,也就是说这个字段的整数位最大是8位。

NUMERIC数据类型使用标准、可变长度的内部格式来存储数字。
修改完整性约束条件
可以使用ALTER TABLE语句修改表中的完整性规则。
例5.12
去掉例5.10Student表中对性别的限制。

ALTER TABLE Student
DROP CONSTRAINT C4;

例5.13
修改Student中的约束条件,要求学号改为在90000~99999之间,年龄由小于30改为小于40.

ALTER TABLE Student
	DROP CONSTRAINT C1;
ALTER TABLE Student
	ADD CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999);
ALTER TABLE Student
	DROP CONSTRAINT C3;
ALTER TABLE Student
	DROP CONSTRAINT C3 CHECK (Sage<40);

触发器(Trigger)

触发器是用户定义在关系表上的一类由事件驱动的特殊过程。一旦定义,触发器将被保存在数据库服务器中。
定义触发器

CREATE TRIGGER <触发器名> 
 /*每当触发事件发生时,该触发器被激活*/
{BEFORE|AFTER}<触发事件> ON <表名>
   /*指明触发器激活的时间是在执行触发事件前或后*/
REFERENCING NEW|OLD ROW AS<变量>
/*REFERENCING指出引发的变量*/
FOR EACH {ROW|STATEMENT}
/*定义触发器的类型,指明动作执行的频率*/
[WHEN <触发条件>]<触发动作体>
/*仅当触发条件为真时才执行触发动作体*/

1、只有创建表的用户才可以在表上创建触发器,并且一个表上只能创建一定数量的触发器。
2、触发器名
同一模式下,触发器名必须是唯一的,并且触发器名和表名必须在同一模式下。
3、表名
触发器只能定义在基本表上,不能定义在视图上。
4、触发事件
触发事件—INSERT\DELETE\UPDATE
UPDATE FOR<触发列,。。。。>
5、触发器类型
行级触发器(FOR EACH ROW) 100次
语句触发器 一次
6、触发条件
触发器被激活时,只能当触发条件为真时触发动作才执行,否则触发动作体不执行,如果忽略WHEN触发条件,则触发动作在触发器激活后立即执行。
7、触发动作体
触发动作体既可以是一个匿名PL\SQL动作块,也可以是对已创建存储过程的调用。
如果触发动作体执行失败,激活触发器的事件(即对数据库的增、删、该操作)就会终止执行,触发器的目标表或触发器可能影响的其他对象不发生任何变化。
BEGIN({)
IF AND
THEN(然后怎么样);
END IF;
END;(})
例5.21
当对表SC的Grade属性进行修改时,若分数增加了10%,则将此次操作记录到另一个表SC_U(Sno,Cno,Oldgrade,Newgrade)中,其中Oldgrade是修改前的分数,Newgrade是修改后的分数。
先建表SC_U

CREATE TABLE SC_U
(
Sno CHAR(9) PRIMARY KEY,
Cno CHAR(9),
OldGrade SMALLINT,
NewGrade SMALLINT
);

CREATE TRIGGER SC_T 
 /*SC_T是触发器的名字*/
AFTER UPDATE OF Grade ON SC
/*UPDATE OF Grade ON SC是触发事件*/
/*AFTER是触发的时机,表示当时对SC的Grade属性修改完后再触发下面的规则*/
REFERENCING
   OLDROW AS OldTuple,
   NEWROW AS NewTuple,
FOR EACH ROW
/*行级触发器,即每执行一次Grade的更新,下面的规则就执行一次*/
WHEN(NewTuple.Grade >= 1.1*OldTuple.Grade)
/*触发条件,只有该条件为真时才执行*/
/*下面的insert操作*/
    INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade)
	VALUES(OldTuple.Sno,OldTuple.Cno,Grade,NewTuple.Grade);

报错:“AFTER”附近有语法错误。
此地方是因为T-SQL与标准SQL的写法不同,因改为

CREATE TABLE SC_U
(
Sno CHAR(9) PRIMARY KEY,
Cno CHAR(9),
OldGrade SMALLINT,
NewGrade SMALLINT
);

CREATE TRIGGER SC_T
ON SC
FOR UPDATE 
AS
    declare @OLD SMALLINT
	declare @NEW SMALLINT
	declare @SNO CHAR(9)
	declare @CNO CHAR(4)
IF(UPDATE(Grade))
    BEGIN
	select @OLD =Grade FROM DELETED
	select @NEW =Grade FROM INSERTED
	select @SNO =Sno FROM SC
	select @Cno =Cno FROM SC
	IF(@NEW>=1.1*@OLD)
    INSERT INTO SC_U(Sno,Cno,Oldgrade,Newgrade)
	VALUES(@SNO,@CNO,@OLD,@NEW)
END

测试:

UPDATE SC
SET GRADE=70
WHERE Sno='201215121' AND Cno='3'

UPDATE SC
SET GRADE=95
WHERE Sno='201215122' AND Cno='3'
SELECT * FROM SC
SELECT * FROM SC_U

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第3张图片【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第4张图片
例5.22
将每次对表Student的操作所增加的学生个数记录到表Sutdent-InsertLog中。

/*新建StudentInsertLog表来存储学生人数*/
CREATE TABLE StudentInsertLog
(
Number INT
)
/*新建StudentInsertLogUser表来存储用户名和操作时间*/
CREATE TABLE StudentInsertLogUser
(
UserName nchar(10),
DateAndTime datetime
)
/*新建触发器Student_Count,当插入新的学生记录时,触发器启动,自动在StudentInsertLog记录学生人数*/
CREATE TRIGGER Student_Count
ON Student  	         
AFTER
INSERT
AS 
    INSERT INTO StudentInsertLog(Number)
	  SELECT COUNT(*) FROM Student
/*新建触发器Student_Time,当插入新的学生记录时,触发器启动,自动在StudentInsertLogUser记录用户名和操作时间*/
CREATE TRIGGER Student_Time
ON Student  	         
AFTER
INSERT
AS 
	declare @UserName    nchar(10)
	declare @DateTime    datetime

	select @UserName = system_user
	select @DateTime = CONVERT(datetime,GETDATE(),120) --2018-04-11 16:33:10

	INSERT INTO StudentInsertLogUser(UserName,DateAndTime)
	VALUES (@UserName,@DateTime)
/*测试触发器效果*/
INSERT
INTO  Student
VALUES ('201215135','王五','男',18,'CS');
SELECT * FROM Student
SELECT * FROM StudentInsertLog
SELECT * FROM StudentInsertLogUser

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第5张图片【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第6张图片
例5.23
定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”

/*新建Teacher表*/
CREATE TABLE Teacher
(
Tno CHAR(9),
Tname CHAR(9),
Job CHAR(9),
Salary SMALLINT
);

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第7张图片标准SQL

CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher
REFERENCING NEW row AS newTuple
FOR EACH ROW
BEGIN
	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
  IF UPDATE(Salary)
  BEGIN
  declare @TNO CHAR(9)
  declare @TNAME CHAR(9)
  declare @JOB CHAR(9)
  declare @SALARY SMALLINT

  select @SALARY = Salary FROM INSERTED
  select @TNO = Tno FROM Teacher
  select @TNAME = Tname FROM Teacher
  select @JOB = Job FROM Teacher

  IF(@SALARY<4000 AND @JOB='教授' )
  UPDATE Teacher
  SET Salary=4000
  WHERE Salary<4000 AND Job='教授'
END

测试数据

INSERT 
INTO Teacher
VALUES('2020007','黑黑','教授',3200)

SELECT * FROM Teacher

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第8张图片
激活触发器
触发器执行,是由触发事件激活的,并由数据库服务器自动执行
删除触发器
DROP TRIGGER<触发器名>;
存储过程
有过程SQL语句,经编译和优化后存在数据库服务器中,可以被反复调用,运行速度较快。
优点:
1、效率高
2、降低客户机和服务器之间的通信量
3、方便实施企业规则
创建 执行 修改 删除
创建存储过程

CREATE OR REPLACE PROCEDURE 过程名([参数1,参数2,...]/*存储过程首部*/
AS <过程化SQL>;(例如 DECLARE 定义变量)
/*存储过程体,描述该存储过程的操作*/

例8.8
利用存储过程实现下面的应用:从账户1转指定数额的款项到账户2中。假设账户关系表为Account(Accountnum,Total).
1、建立新表Account,并写入两个用户

DROP TABLE IF EXISTS Account;

CREATE TABLE Account
(
accountnum CHAR(3),  ---账户编号
total FLOAT    ----账户余额
);

INSERT INTO Account VALUES(101,50);
INSERT INTO Account VALUES(102,100);

SELECT * FROM Account

在这里插入图片描述
2、建立存储过程

IF (exists (select * from sys.objects where name = 'Proc_TRANSFER'))
    DROP PROCEDURE Proc_TRANSFER
GO
CREATE PROCEDURE Proc_TRANSFER 
@inAccount INT,@outAccount  INT,@amount FLOAT
 /*定义存储过程TRANSFER,参数为转入账户、转出账户、转账额度*/
AS
BEGIN TRANSACTION TRANS   
   	DECLARE		/*定义变量*/
	@totalDepositOut Float,
	@totalDepositIn Float,
	@inAccountnum INT;
	 /*检查转出账户的余额 */     
	SELECT @totalDepositOut = total FROM Account	WHERE accountnum = @outAccount;
	/*如果转出账户不存在或账户中没有存款*/
	IF @totalDepositOut IS NULL               	   
		BEGIN
			PRINT '转出账户不存在或账户中没有存款'
			ROLLBACK TRANSACTION TRANS; 	   /*回滚事务*/
			RETURN;
		END;
	/*如果账户存款不足*/
	IF @totalDepositOut < @amount     	
		BEGIN
			PRINT '账户存款不足'
			ROLLBACK TRANSACTION TRANS; 				/*回滚事务*/
			RETURN;
		END
	/*检查转入账户的状态 */  
	SELECT @inAccountnum = accountnum  FROM Account	WHERE accountnum = @inAccount;
	/*如果转入账户不存在*/ 
	IF @inAccountnum IS NULL   		                       
		BEGIN
			PRINT '转入账户不存在'
			ROLLBACK TRANSACTION TRANS; 	         	 		/*回滚事务*/
			RETURN;
		END;
	/*如果条件都没有异常,开始转账。*/ 
	BEGIN
		UPDATE Account SET total = total - @amount	WHERE	accountnum = @outAccount; /* 修改转出账户余额,减去转出额 */
		UPDATE Account SET total = total + @amount	WHERE   accountnum = @inAccount; /* 修改转入账户余额,增加转入额 */
		PRINT '转账完成,请取走银行卡'
		COMMIT TRANSACTION TRANS;                       	/* 提交转账事务 */
		RETURN;
	END

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第9张图片
测试:

EXEC	Proc_TRANSFER
		@inAccount = 101,	--转入账户
		@outAccount = 102,	--转出账户
		@amount = 50		--转出金额

SELECT * FROM Account

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第10张图片测试:

EXEC	Proc_TRANSFER
		@inAccount = 102,	--转入账户
		@outAccount = 101,	--转出账户
		@amount = 200		--转出金额

SELECT * FROM Account

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第11张图片测试:

EXEC	Proc_TRANSFER
		@inAccount = 103,	--转入账户
		@outAccount = 101,	--转出账户
		@amount = 50		--转出金额

SELECT * FROM Account

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第12张图片
例8.9
从账户01003815868 转10000元到01003813828账户中

SELECT * FROM Account

INSERT INTO Account VALUES(01003815868,20000)
INSERT INTO Account VALUES(01003813828,10000)
EXEC	Proc_TRANSFER
		@inAccount = 01003813828,	--转入账户
		@outAccount = 01003815868,	--转出账户
		@amount = 10000		--转出金额

SELECT * FROM Account

【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第13张图片【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第14张图片

参考:
https://blog.csdn.net/qq_38975453/article/details/104729884
https://blog.csdn.net/qq_38975453/article/details/104729681

这一篇给我的感觉就是:轻松----->绝望,刚开始写完整性的时候,感觉so easy,都是之前说过的,再写一遍就可以了,然后轻松的过渡到触发器,刚开始定义方面就花费了很多事件,到了例题,标准SQL再SQL SERVER中不能用,又百度了一下,参考别人家的博客,勉勉强强地写下来,到了存储过程,题目很简单,但是要建立存储过程,便变得复杂起来,最后终于迎来了尾声,还是感觉自己棒棒哒!!!

你可能感兴趣的:(【2019-2020春学期】数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION)