数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION

Rowena ·
更新时间:2024-11-10
· 859 次阅读

第五章 数据库完整性
数据库完整性包括:实体完整性,参照完整性,用户定义的完整性

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

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

实体完整性:主码不能为空。
CREATE TABLE 用PRIMARY KEY来设置主码,完成实体完整性。
在定义列时设定列为主码叫做列级定义主码,而在定义完表后再定义表的主码叫做表级定义主码,两种方式都可。

【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 CHAR(4) NOT NULL, Grade SMALLINT, PRIMARY KEY (Sno, Cno), /*在表级定义实体完整性*/ FOREIGN KEY (Sno) REFERENCES Student(Sno), FOREIGN KEY (Cno) REFERENCES Course(Cno) );

参照完整性规则:外码要么为空,要么为被参照关系的主码。
CREATE TABLE中用FOREIGN KEY短语定义哪些列为外码,用REFERENCES短语指明这些外码参照哪些表的主码。

参照完整性检查和违约处理:
对于被参照表Student和参照表SC有四种违约方式:
1.在参照表SC中插入元组,此元组的Sno属性值在被参照表中找不到一个元组。其Sno值与其相等,拒绝处理。
2.修改SC表中的一个元组,修改后该院组的Sno属性值在表Student中没有元组,其Sno属性值与之相等,拒绝处理。
3.从Student表中删除一个元组,SC中某些元组的Sno属性值在表Student中没有对应的相同Sno属性值元组。拒绝/级连删除/设置为空值。
4.修改Student表的Sno属性,使得SC表中某些元组的Sno属性在Student表中没有Sno属性对应,拒绝/级连删除/设置为空值。

处理策略:
1拒绝NO ACTION执行:不允许执行此操作,一般为默认策略。
2级联CASCADE操作:当删除和修改被参照表Student中的元组导致与参照表SC不一致时,删除或修改参照表中的所有导致不一致的元组。
3设置为空值:当删除和修改被参照表Student中的元组导致与参照表SC不一致时,将参照表中不一致的地方设置为空。

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

CREATE TABLE SC (Sno CHAR(9) NOT NULL, Cno CHAR(4) 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 NO ACTION /*当删除course 表中的元组造成了与SC表不一致时拒绝删除*/ ON UPDATE CASCADE /*当更新course表中的cno时,级联更新SC表中相应的元组*/ );

在将Sno,Cno属性作为SC的外码时,在后面加上ON DELECT(UPDATE) CASCADE(NO ACTION);
这里可以看到,若修改删除Student中的数据,则删除修改SC中相应的数据;修改Course中的Cno时,修改SC中的Cno,删除Course中的Cno时,不允许删除。

用户定义完整性:
1.属性上的约束条件:
列值非空(NOT NULL);列值唯一(UNIQUE);检查列值是否满足一个条件表达式(CHECK);
属性上的约束条件检查和违约处理:
插入元组或修改属性的值时,关系数据库管理系统检查属性上的约束条件是否被满足,如果不满足则操作被拒绝执行。

2.元组上的约束条件:
用CHECK短语定义元组上的约束条件,即元组级的限制。
元组上的约束条件检查和违约处理:
插入元组或修改属性的值时,关系数据库管理系统检查元组上的约束条件是否被满足,如果不满足则操作被拒绝执行。

【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), );

Sno属性不允许取空值,Cno属性不允许取空值,Grade属性不允许取空值。

如果在标记定义实体完整性,则此时隐含Sno,Cno不能取空值。

在这里插入图片描述

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

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

Dname列的值唯一(UNIQUE), 并且不能取空值(NOT NULL).
Deptno不能为空。
在这里插入图片描述

【5.7】 Student表的Ssex只允许取“男”或“女”。

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

性别只能是 ‘男’或者‘女’。CHECK用来指定列值应该满足的条件。

INSERT INTO Studen VALUES('2014','xig','中',17,'M'); --INSERT 语句与 CHECK 约束"CK__Studen__Ssex__0B91BA14"冲突。该冲突发生于数据库"Student",表"dbo.Studen", column 'Ssex'。

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

CREATE TABLE SC (Sno CHAR(9) , Cno CHAR(4), Grade SMALLINT CHECK (Grade>=0 AND Grade <=100), PRIMARY KEY (Sno,Cno), FOREIGN KEY (Sno) REFERENCES Student(Sno), FOREIGN KEY (Cno) REFERENCES Course(Cno) ); INSERT INTO SC VALUES('20121512 ','1',110); --INSERT 语句与 CHECK 约束"CK__SC__Grade__0E6E26BF"冲突。该冲突发生于数据库"Student",表"dbo.SC", column 'Grade'。

【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.%') );

CHECK定义了Ssex和Sname的约束条件。

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

CREATE TABLE Studen (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 (Ssex IN ( '男','女')), CONSTRAINT StudentKey PRIMARY KEY(Sno) );

在Student表上建立了5个约束条件,包括主码约束(命名为StudentKey)以及C1、C2、C3、C4四个列级约束。
提示:数据库中已存在名为 ‘C1’ 的对象。忘了啥时候有过了,就把C1写成C1_.

约束一栏中没有C2,NULL和NOT NULL 是不被放在约束栏里的。
在这里插入图片描述

完整性约束命名子句:CONSTRAINT
包括NOT NULL、UNIQUE、PRIMARY KEY短语、FOREIGN KEY短语、CHECK短语等。
修改表中的完整性限制:使用ALTER TABLE语句修改表中的完整性限制。

【5.11】建立教师表TEACHER,要求每个教师的应发工资不低于3000元

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 TEACHERKey FOREIGN KEY(Deptno) REFERENCES DEPT(Deptno), CONSTRAINT C1 CHECK(Sal+Deduct>=3000) );

【5.12】去掉例5.10 Student表中对性别的限制

ALTER TABLE Studen DROP CONSTRAINT C4;

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

ALTER TABLE Studen DROP CONSTRAINT C1_; ALTER TABLE Studen ADD CONSTRAINT C1_ CHECK (Sno BETWEEN 900000 AND 999999); ALTER TABLE Studen DROP CONSTRAINT C3; ALTER TABLE Studen ADD CONSTRAINT C3 CHECK(Sage<40);

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

定义触发器格式:

CREATE TRIGGER {BEFORE | AFTER} ON REFERENCING NEW|OLD ROW AS FOR EACH {ROW | STATEMENT} [WHEN ]

触发事件:INSERT、DELECT或UPDATE;UPDATE OF,即进一步指明修改哪些列时激活触发器。
AFTER表示在触发事件的操作执行之后激活触发器,BEFORE表示在触发事件的操作执行之前激活触发器。
FOR EACH ROW:行级触发器(每一行触发一次);FOR EACH STATEMENT:语句级触发器;

【5.21】当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中SC_U(Sno,Cno,Oldgrade,Newgrade),其中Oldgrade是修改前的分数,Newgrade是修改后的分数。

CREATE TRIGGER SC_T AFTER UPDATE OF Grade ON SC REFERENCING OLD row AS OldTuple, NEW row AS NewTuple 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) --“AFTER”附近有语法错误。

创建好SC_U(Sno,Cno,Oldgrade,Newgrade)。执行上列语句后报错。
在T-SQL中,应写成:

CREATE TRIGGER SC_T ON SC AFTER UPDATE AS --declare @变量名称 变量类型 declare @Sno char(15) declare @Cno char(4) declare @Oldgrade SMALLINT declare @Newgrade SMALLINT --IF(UPDATE(Grade)),返回一个布尔值,指示是否对表或视图的指定列进行了 INSERT 或 UPDATE 尝试。测试触发器是否应执行UPDATE操作。 IF(UPDATE(Grade)) SELECT @OLDgrade =Grade FROM DELETED SELECT @NEWgrade =Grade FROM INSERTED SELECT @SNO =Sno FROM SC SELECT @CNO =Cno FROM SC INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade) VALUES(@Sno,@Cno,@Oldgrade,@Newgrade);

数据测试:
在这里插入图片描述

UPDATE SC SET Grade=100 WHERE Grade<100; SELECT * FROM SC_U

SC_U中结果,只有改后分数大于原来分数10%的记录。
在这里插入图片描述

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

--新建表,存储学生人数 CREATE TABLE StudentInsertLog ( Numbers INT ) --新建表,存储用户名和操作时间 CREATE TABLE StudentInsertLogUser ( UserName nchar(10), DateAndTime datetime ) --新建触发器,当插入新的学生记录时,触发器启动,自动在StudentInsertLog记录学生人数 CREATE TRIGGER Student_Count ON Student AFTER INSERT AS INSERT INTO StudentInsertLog(Numbers) SELECT COUNT(*) FROM Student --当插入新的学生记录时,触发器启动,自动在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) INSERT INTO StudentInsertLogUser(UserName,DateAndTime) VALUES (@UserName,@DateTime) --测试触发器效果 INSERT INTO Student VALUES ('201215135','王五','男',18,'CS'); SELECT * FROM Student SELECT * FROM StudentInsertLog SELECT * FROM StudentInsertLogUser

在这里插入图片描述
在这里插入图片描述

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

--创建Teacher表 CREATE TABLE Teacher ( Name CHAR(10), Salary SMALLINT, Job CHAR(10) ) --加入数据 INSERT INTO Teacher(name,Salary,Job) VALUES('清风',3500,'教授'); INSERT INTO Teacher(name,Salary,Job) VALUES('朗月',4500,'教授'); INSERT INTO Teacher(name,Salary,Job) VALUES('枝枝',3000,'副教授'); --创建触发器 CREATE TRIGGER Insert_Or_Update_Sal ON Teacher FOR INSERT , UPDATE AS declare @Salary SMALLINT 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 INSERT INTO Teacher VALUES('yuan',3200,'教授'); SELECT * FROM Teacher

得到如下数据:
在这里插入图片描述

存储过程:由过程化SQL语句,经编译和优化后存储在数据库服务器中,可以被反复调用,运行速度较快。

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

--建立新表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

在这里插入图片描述

--建立存储过程 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 --正常情况 EXEC Proc_TRANSFER @inAccount = 101, --转入账户 @outAccount = 102, --转出账户 @amount = 50 --转出金额 SELECT * FROM Account

在这里插入图片描述

--余额不足情况 EXEC Proc_TRANSFER @inAccount = 101, --转入账户 @outAccount = 102, --转出账户 @amount = 51 --转出金额 --账户存款不足 --账户不存在情况 EXEC Proc_TRANSFER @inAccount = 100, --转入账户 @outAccount = 102, --转出账户 @amount = 50 --转出金额 --转入账户不存在 EXEC Proc_TRANSFER @inAccount = 101, --转入账户 @outAccount = 103, --转出账户 @amount = 50 --转出金额 --转出账户不存在或账户中没有存款

【8.9】从账户01003815868转10000原到01003813828账户中

DROP TABLE IF EXISTS Account; CREATE TABLE Account ( accountnum CHAR(15), -- 账户编号 total FLOAT -- 账户余额 ); INSERT INTO Account VALUES(01003815868,20000) INSERT INTO Account VALUES(01003813828,10000) EXEC Proc_TRANSFER @inAccount = 01003813828, --转入账户 @outAccount = 01003815868, --转出账户 @amount = 10000 --转出金额 SELECT * FROM Account

在这里插入图片描述

参考:

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述


作者:鹤阕



SQL PROCEDURE CONSTRAINT 数据 check sql练习 trigger 数据库

需要 登录 后方可回复, 如果你还没有账号请 注册新账号