数据库学习12 - 第五章例题

文章目录

  • 5.1 实体完整性
  • 5.2 参照完整性
  • 5.3 用户定义的完整性
    • 5.3.1 属性上的约束条件
    • 5.3.2 元组上的约束条件
  • 5.4 完整性约束命名子句
    • 1. 完整性约束命名子句
    • 2. 修改表中的完整性限制
  • 5.6 断言
    • 1. 创建断言的语句格式
    • 2. 删除断言的语句格式
  • 5.7 触发器
    • 1. 定义触发器
    • 2. 激活触发器
    • 3. 删除触发器
  • 8.3存储过程
    • 1. 创建存储过程:
    • 2. 执行存储过程
    • 3. 修改存储过程:
    • 4. 删除存储过程:

数据库的完整性是指数据的正确性和相容性。 数据的正确性是指数据是否符合现实世界语义、反映当前实际状况;数据的相容性是指数据库同一对象在不同关系表中的数据是符合逻辑。

5.1 实体完整性

关系模型的实体完整性在CREATE TABLE中用 PRIMARY KEY定义,分为列级约束条件和表级约束条件。定义完成后,需要检查:
(1)主码值是否唯一,如果不唯一则拒绝插入或修改。
(2)主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。

例题5.1:将Student表中的Sno属性定义为码。

1)在列级定义码:
create table Student
(Sno char(9) primary key,
Sname char(20) not null,
Ssex char(2),
Sage smallint,
Sdept char(20));2)在表级定义码:
create table Student
(Sno char(9),
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.2 参照完整性

关系模型的参照完整性在CREATE TABLE 中用FOREIGN KEY短语定义那些列为外码,用REFERENCES短语指明这些外码参照那些表的主码。

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

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

create table SC
   (Sno char(9) not null,
	Cno char(4) not null,
	Grade smallint,
	primary key (Sno,Cno),
			/*在表级定义实体完整性,Sno、Cno都不能取空值*/
	foreign key(Sno) references Student(Sno)
			/*在表级定义参照完整性*/
		on delete cascade	
			/*删除Student元组时,级联删除SC表中相应的元组*/
		on update cascade	
			/*Student表更新Sno时,级联更新SC表中相应的元组*/
	foreign key(Cno) references Course(Cno)
			/*在表级定义参照完整性*/
		on delete no action	
			/*当删除Course表中的元组导致与SC表不一致时拒绝删除*/
		on update cascade	
			/*当更新Course表中的Cno时级联更新SC表中相应的元组*/
);

5.3 用户定义的完整性

5.3.1 属性上的约束条件

在CREATE TABLE中定义属性的同时,根据应用要求定义属性上的约束条件,包括:

· 列值非空(not null)

· 列值唯一(unique)

· 检查列值是否满足一个条件表达式(check短语)

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

create table SC
(Sno char(9) not null,      //Sno不能为空
 Cno char(4) not null,     //Cno不能为空
 Grade smallint not null, //Grade不能为空
 primary key (Sno,Cno),
  ……
);

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

create table DEPT
(Deptno numeric(2),
 Dname char(9) unique not null, //要求Dname列值唯一,且不能为空值
 Location_ char(10),
 primary key(Deptno)
);

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

create table Student
(Sno char(9) primary key,
 Sname char(20) 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),
 Cno char(4),
 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)
);

5.3.2 元组上的约束条件

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

create table Student
(Sno char(9),
 Sname char(20) not null,
 Ssex char(2),
 Sage smallint,
 Sdept char(20),
 primary key(Sno),
 check(Ssex='女'or Sname not like 'Ms.%')
);
//只有当性别是女时,或者性别不是女(性别为男)但名字没有以Ms. 打头时通过。

5.4 完整性约束命名子句

1. 完整性约束命名子句

:CONSTRAINT <完整性约束条件名><完整性约束条件>
<完整性约束条件>包括: not null、unique、primary key、foreign key、check 短语等。

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

create table Student
(Sno numeric(9)
  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)
);

例5.11: 建立教师表Teachear,要求每个教师的应发工资不低于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)
);

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

使用ALTER TABLE语句修改表中的完整性限制。

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

alter table Student
drop constraint C4;

例5.13: 修改表Student中的约束条件,学号改在900000~999999之间,年龄小于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);

5.6 断言

1. 创建断言的语句格式

· CREATE ASSERTION <断言名>

例5.18: 限制数据库课程最多60名学生选修。

create assertion ASSE_SC_DB_NUM
	check(60>=(select count(*)
		from SC,Course 
		where SC.Cno=Course.Cno and Course.Cname='数据库')
);
//每对SC表插入一组元组,断言都会被除触发检查,直到达60人时会拒绝插入。

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

create assertion ASS_SC_CNUM1
	check(60>=all(select count(*) 
	from SC 
	group by Cno)
);

例5.20: 限制每个学期每一门课程最多60名学生选修。

alter table SC add term date;--增加term属性,类型是date
create assertion ASSE_SC_CNUM2
	check(60>=all(select count(*)
				  from SC 
				  group by Cno,term)
);

2. 删除断言的语句格式

DROP ASSERTION <断言名>;

不同于SQL,在T-SQL中不能断言。

5.7 触发器

1. 定义触发器

SQL建立触发器的一般语句为:

CREATE TRIGGER <触发器名>			//每当触发事件发生时,该触发器被激活
{BEFORE|AFTER}<触发事件>ON<表名>		//指明触发器激活的时间

REFERENCING NEW|OLD ROW AS <变量>	//REFERENCING指出引用的变量
FOR EACH{
    ROW|STATEMENT}		       //定义触发器的类型,指明动作体执行的频率
[WHEN <触发条件>]<触发动作体>	  //仅当触发器条件为真时才执行触发动作体

只有当触发条件为真时触发动作体才执行,否则不执行。如果省略 WHEN 触发条件,则触发动作体在触发器激活后立即执行。

例5.21:当对SC表的Grade属性进行修改时,若分数增加了10%,则将操作记录到另一个表中。

1)标准SQLcreate trigger SC_T
alter update of Grade on SC
referencing 
	old row as OldTuple,
	new row as NewTuple,
for ecah row
when (NewTuple.Grade>=1.1*OldTuple)
	insert into SC_U(Sno,Cno,OldGrade,NewGrade)
	values(OldTuple.Sno,OldTuple.Cno,OldTuple.Grade,NewTuple.Grade);
	
2)T-SQLcreate trigger SC_T
on SC for update
as
	declare @Sno varchar(15),
			@Cno varchar(10),
			@new_grade smallint,
			@old_grade smallint;
	select @Sno=Sno,@Cno=Cno,@new_Grade=Grade from inserted;
	select @old_Grade=Grade from deleted;
	if(@new_grade>@old_grade*1.1)
		begin
			insert into SC_U(Sno,Cno,Old,New)
			values(@Sno,@Cno,@old_Grade,@new_Grade);
		end

例5.22:将每次对表Student 的插入操作所增加的学生个数记录添加到表Student-InsertLog 中。

1)标准SQLcreate trigger Student_Count
after insert on Student
referencing 
new table as delta
for each statement
insert into Student_InsertLog(Numbers)
select count(*) from delta;
	
2)T-SQLcreate trigger Student_Count
on Student after insert
as
insert into Student_InsertLog(Numbers)
select count(*) from Student;

例5.23:为教师表定义完整性规则下“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。

1)标准SQLcreate trigger Insert_Or_Update_Sal
before insert ot 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;
	
2)T-SQLcreate trigger Insert_Or_Update_Sal
on Teacher for insert,update
as 
declare @Eno numeric(4,0),
		@Ename varchar(10),
		@Job varchar(8),
		@Sal numeric(7,2),
		@Deduct numeric(7,2),
		@Deptno numeric(2,0);
	select @Eno=Eno,@Ename=Ename,@Job=Job,@Sal=Sal,@Deduct=Deduct,
	@Deptno=Deptno,from inserted;
if(@Sal<4000 and @Job='教授')
begin 
update Teacher set @Sal=4000 
end;

2. 激活触发器

执行顺序:
(1)执行该表上的before触发器
(2)激活触发器的SQL语句
(3)执行该表上的AFTER触发器

· 谁先创建谁先执行。

3. 删除触发器

删除语句:DROP TRIGGER <触发器名>ON <表名>;

8.3存储过程

1. 创建存储过程:

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

1)标准SQL

create or replace procedure TRANSFER(inAccount int,outAccount  int,amount float) 
//定义存储过程TRANSFER,参数为转入账户、转出账户、转账额度*
	as declare		//定义变量
	    totalDepositOut float;
        totalDepositIn float;
		inAccountnum int;
begin                         	      //检查转出账户的余额 
	       select Total into totalDepositOut from Accout 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 = inAccount;
   if inAccount is null then 		 //如果转入账户不存在                     
	  rollback; 	         	 		//回滚事务
	  return;
   end if;
   update Account set total = total - amount
   where accountnum = outAccount;   //修改转出账户余额,减去转出额 
   update Account set total = total + amount 
   where   accountnum = inAccount;  //修改转入账户余额,增加转入额 
   commit;                       	// 提交转账事务 
end;

2)T-SQL:

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
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 = 00000,	--转入账户
		@outAccount = 00001,	--转出账户
		@amount = 50		--转出金额

select * from  Account

2. 执行存储过程

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

例8.9: 从账户01003815868转10000元到01003813828账户中。

call procedure  transfer(01003813828,01003815868,10000);

3. 修改存储过程:

ALTER PROCEDURE 过程名1 RENAME TO 过程名2;

也可以重新编译一个存储过程:

ALTER PROCEDURE 过程名 COMPILE;

4. 删除存储过程:

DROP PROCEDURE 过程名();

…………………………………………………………………………….

在这里插入图片描述
以上就是文章全部内容,感谢阅读。

你可能感兴趣的:(数据库,SQL,server,sql)