【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数

这里写目录标题

      • 实体完整性&参照完整性
            • [例5.1] 将Student表中的Sno属性定义为码
            • [例5.2] 将SC表中的Sno,Cno属性组定义为码
            • [例5.3]定义SC中的参照完整性
        • 参照完整性的违约处理
            • [例5.4] 显式说明参照完整性的违约处理示例
      • 用户定义的完整性
        • CHECK
            • [例5.7] Student表的Ssex只允许取“男”或“女”。
            • [例5.8] SC表的Grade的值应该在0和100之间。
            • [例5.9]当学生的性别是男时,其名字不能以Ms.打头。
      • 完整性约束命名子句
        • 删除约束
        • 修改约束
      • 断言assertion
            • [例5.18] 限制数据库课程最多60名学生选修
            • [例5.19]限制每一门课程最多60名学生选修
            • 删除断言
      • 触发器trigger
        • 定义触发器
            • [例5.21]当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中:SC_U(Sno,Cno,Old,New)
            • [例5.22] 将每次对表Student的插入操作所增加的学生个数记录到表StudentInsertLog中。
    • --未完待续... 还差 触发器这一个例子以及存储过程和函数部分。 今天就到此为止了,明天还想要早起。 明天上午一定写完这个。
      • 续:
            • [例5.23] 定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。
      • 存储过程
          • 创建存储过程
            • 模拟转账
          • 执行存储过程
          • 修改存储过程
          • 删除存储过程
      • 函数

实体完整性&参照完整性

我们之前建表的时候已经用过这些,实体完整性和参照完整性我们之前已经做过例子,这里只进行简单的演示。

[例5.1] 将Student表中的Sno属性定义为码

在列里面定义:

create Table Student
(Sno char(9) PRIMARY KEY,
 Sname char(9) NOT NULL,
 Ssex char(2),
 Sage smallint,
 Sdept char(20));

它也可以在行级定义,而且有些情况下, 比如两个列共同作为主码时,只能在行级定义。

 create Table Student
(Sno char(9) ,
 Sname char(9) NOT NULL,
 Ssex char(2),
 Sage smallint,
 Sdept char(20),
 PRIMARY KEY(Sno);
[例5.2] 将SC表中的Sno,Cno属性组定义为码
CREATE TABLE SC
			(Sno NCHAR(11),
			 Cno NCHAR(4),
			 Grade SMALLINT,
			 PRIMARY KEY(Sno,Cno),
			 FOREIGN KEY (Sno) REFERENCES Student(Sno),
			 FOREIGN KEY (Cno) REFERENCES Course(Cno)
			);
[例5.3]定义SC中的参照完整性

例码同上

参照完整性的违约处理

【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第1张图片

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

要说明的是,这是针对被参照表的操作。参照表SC可以delete,insert一个不符合外键规则的直接拒绝;而被参照表,比如Student表,一个学生的信息修改了,那么sc表里是否跟着修改还是?
上图说明了有三种设置,拒绝,级联修改/删除,设置为空值。

create Table SC2
(Sno CHAR(9) NOT NULL, 
Cno CHAR(4)  NOT NULL,  
Grade SMALLINT,
PRIMARY KEY (Sno, Cno),   

FOREIGN KEY (Sno) REFERENCES Student(Sno)
on update cascade
on delete cascade, 

FOREIGN KEY (Cno) REFERENCES Course(Cno)    
on update cascade
on delete no action, --拒绝
);

用户定义的完整性

这里分为属性上约束还有元组的约束。
列上的:not null,unique,check
元组上的:check
关于not null和unique,我们之前就做过例子,在这里不做示题
关于check

CHECK

关于列的(也就是只独立处理一个属性的)

[例5.7] Student表的Ssex只允许取“男”或“女”。
create Table Student2
(Sno char(9) PRIMARY KEY,
 Sname char(9) NOT NULL,
 Ssex char(2) check(Ssex IN('男','女')),--这里发生了变化
 Sage smallint,
 Sdept char(20));
[例5.8] SC表的Grade的值应该在0和100之间。
create Table SC3
(Sno CHAR(9) NOT NULL, 
Cno CHAR(4)  NOT NULL,  
Grade SMALLINT check (Grade>=0 AND Grade<=100),--这里发生了变化

PRIMARY KEY (Sno, Cno),   
FOREIGN KEY (Sno) REFERENCES Student(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno)
);

check里面就是写了个条件
关于行级的

[例5.9]当学生的性别是男时,其名字不能以Ms.打头。
create Table Student3
(Sno char(9) PRIMARY KEY,
 Sname char(9) NOT NULL,
 Ssex char(2) check(Ssex IN('男','女')),
 Sage smallint,
 Sdept char(20),
 check (Ssex='女' OR Sname NOT like 'Mr.%')
 );

【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第2张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第3张图片

完整性约束命名子句

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

注意是子句,他也是嵌入到create里面写的。其实也就是多了一个关键字和一个你自己命名的名字。
这是列级的

create Table Student4
(Sno char(9) 
constraint Student_PK_Sno PRIMARY KEY,--this
 Sname char(9)
 constraint Student_NN_Sname NOT NULL,--this
 Ssex char(2) 
 constraint Student_check_Ssex check(Ssex IN('男','女')),--this
 Sage smallint,
 Sdept char(20),
 check (Ssex='女' OR Sname NOT like 'Mr.%')
 );

行级类似

 create Table SC4
(Sno CHAR(9) NOT NULL, 
Cno CHAR(4)  NOT NULL,  
Grade SMALLINT check (Grade>=0 AND Grade<=100),

constraint SC_PK PRIMARY KEY (Sno, Cno),   
constraint SC_FK1  FOREIGN KEY (Sno) REFERENCES Student(Sno),
constraint SC_FK2  FOREIGN KEY (Cno) REFERENCES Course(Cno)
);

删除约束

alter table Student4
drop constraint Student_PK_Sno;

修改约束

通过先删除旧的,再添加新的方法修改。

alter table Student4
drop constraint Student_PK_Sno;
alter table Student4
add constraint Student_PK_Sno PRIMARY KEY(Sno,Sname);

断言assertion

断言是标准sql里的东西,t-sql并没有这个关键词。老师说可以用rule替代。
这里只做标准sql里的例子。
都是约束,为啥要用断言啊?直接check不好吗?
断言可以定义比较复杂的约束。
比如下面的例子:
我们之前的约束似乎没有办法做。

[例5.18] 限制数据库课程最多60名学生选修
create assertion ASSE_SC_DB_NUM
check (60>=(select count(*)
		   from course,sc
		   where course.Cno=sc.Cno AND course.Cname='数据库')); 
[例5.19]限制每一门课程最多60名学生选修
create assertion ASSE_SC_CNUM
check (60>=all(select count(*)
		   from sc
		   group by cno));
删除断言
drop assertion asse_name

注意:T-SQL 中没有 ASSERTION 功能。 类似的有RULE,但使用方法不同: 上下文中不允许使用子查询,只允许使用标量表达式。 例如: CREATE RULE sex_rule AS @sex in (‘男’,‘女’) 使用Constraint基本能完成功能,不建议使用RULE。

触发器trigger

定义触发器

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

这是标准sql哈。

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

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

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

先创建表。

create table SC_U(Sno char(9),
				  Cno char(4),
				  Old smallint,
				  New smallint);

这是操作。

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

但是我们发现sqlserver中上面的语句中报了错。
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第4张图片
他的语法格式类似这种

-- SQL Server Syntax  
-- Trigger on an INSERT, UPDATE, or DELETE statement to a table or view (DML Trigger)  
  
CREATE [ OR ALTER ] TRIGGER [ schema_name . ]trigger_name   
ON { table | view }   
[ WITH <dml_trigger_option> [ ,...n ] ]  
{ FOR | AFTER | INSTEAD OF }   
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }   
[ WITH APPEND ]  
[ NOT FOR REPLICATION ]   
AS { sql_statement  [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }  

又查了好多博客,缺缺补补写出来了,但是不知道是否是标准写法。
首先referencing用了inserted和deleted表替代了;when语句我也不知道是否被替代了,但是可以用if来实现类似功能,但是是在那个过程里面执行的。
总之是实现那个功能了。

CREATE TRIGGER  SC_T	
ON SC
AFTER UPDATE 
as
begin
	declare @old int ,@new int ,@sno char(9), @cno char(4)
	select @old=Grade from deleted
	select @new=Grade from inserted
	select @sno=Sno from inserted
	select @cno=Cno from inserted
	if(@new>=1.1*@old)
	begin
	insert 
	into SC_U(Sno,Cno,Old,New)  
	VALUES(@sno,@cno,@old,@new)
	print'添加了一条数据---SC_U'
	end
end;

【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第5张图片
(这个之前是80分)
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第6张图片
(这个之前是95)看来是成功了。
还有就是关于for each row和for each statement,本来老师说可以做个实验加深一下印象,但是发现似乎sqlserver里面不能使用这个东西。(oracle支持)

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

标准sql:

CREATE TRIGGER Student_Count
	AFTER INSERT ON Student  	         
	REFERENCING
     	NEW TABLE AS DELTA
	FOR EACH STATEMENT  
	      	INSERT INTO StudentInsertLog (Numbers)
   		SELECT COUNT(*) FROM DELTA

t-sql
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第7张图片

create trigger Student_Count
on Student
after insert
as
begin
	declare @oldnum int , @newnum int
	select @oldnum= count(*) from deleted
	select @newnum= count(*) from inserted
	print 'old:'
	print @oldnum
	print ' new'
	print @newnum
end

由此发现,deleted是删除的表,不是我刚开始想的 旧表;inserted是插入数据的表,而不是我以为的新表。

–未完待续…
还差 触发器这一个例子以及存储过程和函数部分。
今天就到此为止了,明天还想要早起。
明天上午一定写完这个。

还有就是触发器这里t-sql和sql差的太多了。我百度了好久。
还有就是 五一竟然不放假?!
真的开学到现在还没歇过几天。
呜呜呜,晚安

续:

终究还是我食言了,上午没能写完。现在是下午两点,继续:

[例5.23] 定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。
CREATE TRIGGER Insert_Or_Update_Sal 
         BEFORE INSERT OR UPDATE ON Teacher  
         			            
          FOR EACH ROW      
          BEGIN                           
             	IF (new.Job='教授') AND (new.Sal < 4000) 
             	 THEN  new.Sal :=4000;                
           	 END IF;
        END;                               

至于删除触发器

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

tsql里面不用加on和表明,也不能加。

存储过程

创建存储过程

先说标准sql

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

首先建表插数据哈

create table Account(Accountnum char(3),total float);
insert into Account values('01',100),('02',100);
create or replace procedure Transfer(inAccount int ,outAccount int, amount float)
as
	declare 
	totalDepositOut float;
	totalDepositIn float;
	inAccountnum int;
begin
	select total into totalDespositOut from Account
	where Accountnum = outAccount;
	if totalDespositOut is NULL then--没有转出账户
	rollback;
	return ;
	end if;
	if totalDespositOut<amount then--转出账户钱不够
	rollback;
	return ;
	end if;


	select Accountnum into inAccountnum from Account where Accountnum=inAccount;
	if inAccountnum is null then
	--没有转入账户 
	rollback;
	return ;
	end if;

	update Account set total =total -amount
	where Accountnum=outAccout;
	update Account set total =total + amount
	where Accountnum = inAccount;
	commit;
end;

然后是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 
	@totalOut float,
	@totalIn float,
	@inAccountnum int;

	select @totalOut = total from Account where accountnum=@outAccount;
	if @totalOut is NULL
	begin 
		print'账户不存在或者没有存款'
		rollback transaction trans;
		return ;
	end

	if @totalOut<@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'OK!'
		commit transaction trans;
		return ;
	end
	


	
执行存储过程
CALL/PERFORM  PROCEDURE
 过程名([参数1,参数2,...])

t-sql
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第8张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第9张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第10张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第11张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第12张图片
【数据库】第五章例题-完整性-断言-触发器-存储过程以及函数_第13张图片

修改存储过程
ALTER PROCEDURE 过程名1  RENAME TO 过程名2;

t-sql

ALTER { PROC | PROCEDURE } [schema_name.] procedure_name
[ { @parameterdata_type } [= ] ] [ ,…n ]
AS { [ BEGIN ] sql_statement [ ; ] [ ,…n ] [ END ] }
[;]
删除存储过程
DROP  PROCEDURE 过程名()

t-sql:

drop procedure 过程名;

函数

函数就是加了返回值的存储过程
标准sql语法:

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;

链接: t-sql函数.
感觉大作业需要使用sqlserver里的函数,但是现在不想看了,等过几周开始写大作业的时候用到的时候再细细看吧。

本篇完。

你可能感兴趣的:(数据库)