关系模型的实体完整性在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)
);
//只能在表级定义主码
关系模型的参照完整性在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表中相应的元组*/
);
在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.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. 打头时通过。
: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)
);
使用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);
· 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)
);
DROP ASSERTION <断言名>;
不同于SQL,在T-SQL中不能断言。
SQL建立触发器的一般语句为:
CREATE TRIGGER <触发器名> //每当触发事件发生时,该触发器被激活
{BEFORE|AFTER}<触发事件>ON<表名> //指明触发器激活的时间
REFERENCING NEW|OLD ROW AS <变量> //REFERENCING指出引用的变量
FOR EACH{
ROW|STATEMENT} //定义触发器的类型,指明动作体执行的频率
[WHEN <触发条件>]<触发动作体> //仅当触发器条件为真时才执行触发动作体
只有当触发条件为真时触发动作体才执行,否则不执行。如果省略 WHEN 触发条件,则触发动作体在触发器激活后立即执行。
例5.21:当对SC表的Grade属性进行修改时,若分数增加了10%,则将操作记录到另一个表中。
1)标准SQL:
create 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-SQL:
create 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)标准SQL:
create 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-SQL:
create trigger Student_Count
on Student after insert
as
insert into Student_InsertLog(Numbers)
select count(*) from Student;
例5.23:为教师表定义完整性规则下“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。
1)标准SQL:
create 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-SQL:
create 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;
执行顺序:
(1)执行该表上的before触发器
(2)激活触发器的SQL语句
(3)执行该表上的AFTER触发器
· 谁先创建谁先执行。
删除语句:DROP TRIGGER <触发器名>ON <表名>;
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
CALL/PERFORM PROCEDURE 过程名([ 参数1,参数2 …]);
例8.9: 从账户01003815868转10000元到01003813828账户中。
call procedure transfer(01003813828,01003815868,10000);
ALTER PROCEDURE 过程名1 RENAME TO 过程名2;
也可以重新编译一个存储过程:
ALTER PROCEDURE 过程名 COMPILE;
DROP PROCEDURE 过程名();
…………………………………………………………………………….
以上就是文章全部内容,感谢阅读。