一、实体完整性
1、定义实体完整性
对单属性构成的码有两种说明方法:列级约束条件和表级约束条件;
对多个属性构成的码只有一种说明方法:表级约束条件。
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 SC
(Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
Grade SMALLINT,
PRIMARY KEY(Sno,Cno) /*只能在表级定义主码*/
);
2、实体完整性的检查和违约处理
(1)检查主码值是否唯一,如果不唯一则拒绝插入或修改;
(2)检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。
二、参照完整性
1、定义参照完整性
参照完整性在CREATE TABLE中用FOREIGN KEY短语定义外码;
用REFERENCES短语指明这些外码参照的哪些表的主码。
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), /*在表级定义参照完整性*/
);
2、参照完整性检查和违约处理
参照完整性将两个表的相应元组联系起来了,因此,对被参照表和参照表进行增删改时可能破坏参照完整性,必须进行检查以保证这两个表的相容性。
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 /*当删除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表中相应的元组*/
);
三、用户定义的完整性
1、属性上约束条件的定义
(1)不允许空值
CREATE TABLE SC
(Sno CHAR(9) NOT NULL, /*Sno属性不允许空值*/
Cno CHAR(4) NOT NULL, /*Cno属性不允许空值*/
Grade SMALLINT NOT NULL, /*Grade属性不允许空值*/
PRIMARY KEY(Sno,Cno) /*在表级定义实体完整性,隐含了Sno,Cno不允许取空值,在列级不允许取空值的定义可不写*/
.
.
.
);
CREATE TABLE DEPT
(Deptno NUMERIC(2),
Dname CHAR(9) UNIQUE NOT NULL,/*要求Dname列值唯一, 并且不能取空值*/
Location CHAR(10),
PRIMARY KEY(Deptno)
);
(3)用CHECK短语指定列值应该满足的条件
CREATE TABLE Student
( Sno CHAR(9) PRIMARY KEY,
Sname CHAR(8) NOT NULL,
Ssex CHAR(2) CHECK(Ssex IN('男','女')), /*性别属性Ssex只允许取'男'或'女'*/
Sage SMALLINT,
Sdept CHAR(20),
);
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)
);
2、属性上约束条件的检查和违约处理
插入元组或修改属性的值时,关系数据库管理系统检查属性上的约束条件是否被满足,如果不满足则操作被拒绝执行 。
四、元组上的约束条件
1、元组上约束条件的定义
在CREATE TABLE时可以用CHECK短语定义元组上的约束条件,即元组级的限制。
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.%')/*定义了元组中Sname和Ssex两个属性值之间的约束条件*/
);
性别是女性的元组都能通过该项CHECK检查,因为Ssex=‘女’成立;当性别是男性时,要通过检查则名字一定不能以Ms.打头,因为Ssex=‘男’时,条件要想为真值,Sname NOT LIKE 'Ms.%'必须为真值。
2、元组上约束条件的检查和违约处理
插入元组或修改属性的值时,关系数据库管理系统检查元组上的约束条件是否被满足,如果不满足则操作被拒绝执行 。
五、完整性约束命名子句
1、完整性约束命名子句
CONSTRAINT <完整性约束条件名><完整性约束条件>
<完整性约束条件>包括NOT NULL、UNIQUE、PRIMARY KEY短语、FOREIGN KEY短语、CHECK短语等。
CREATE TABLE Student
(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这4个列级约束。
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)
);
2、修改表中的完整性限制
可以用ALTER TABLE语句修改表中的完整性限制。
ALTER TABLE Student
DROP CONSTRAINT C4;
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);
六、触发器
①触发器是用户定义在关系表上的一类由事件驱动的特殊过程。
②触发器类似于约束,但比约束更灵活,可以实施更为复杂的检查和操作,具有更精细更强大的数据控制能力。
1、定义触发器
触发器又叫做 事件 - 条件 - 动作 规则。
SQL使用CREATE TRIGGER命令建立触发器,其一般格式:
CREATE TRIGGER <触发器名>
{BEFORE | AFTER} <触发事件> ON <表名>
REFERENCING NEW|OLD ROW AS<变量>
FOR EACH {ROW | STATEMENT} /*触发器类型*/
[WHEN <触发条件>]<触发动作体>
①只有表的拥有者才可以在表上创建触发器,并且一个表上只能创建一定数量的触发器。
②同一模式下,触发器名必须是唯一的,并且触发器名和表名必须在同一模式下。
③触发器只能定义在基本表上,不能定义在视图上。
④触发事件可以是INSERT、DELETE或UPDATE,也可以是这几个事件的组合。ALTER/BEFORE是触发的时机,ALTER表示在触发事件的操作执行之后激活触发器;BEFORE表示在触发事件的操作执行之前激活触发器。
⑤触发器按照所触发动作的间隔尺寸可以分为行级触发器和语句级触发器。
⑥只有当触发条件为真时触发动作体才执行,否则不执行。
⑦触发动作既可以是一个匿名PL/SQL过程块,也可以是对己创建存储过程的调用。
先建好SC_U表
CREATE TABLE SC_U
(Sno CHAR(9) PRIMARY KEY,
Cno CHAR(9),
OldGrade SMALLINT,
NewGrade SMALLINT
);
标准SQL:
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)
T-SQL:
CREATE TRIGGER SC_T
ON SC
FOR UPDATE
AS DECLARE @OLD SMALLINT
DECLARE @NEW SMALLINT
DECLARE @Sno CHAR(9)
DECLARE @Cno CHAR(5)
IF(UPDATE(Grade))
BEGIN
SELECT @OLD =Grade FROM DELETED
SELECT @NEW =Grade FROM INSERTED
SELECT @Sno =Sno FROM DELETED
SELECT @Cno =Cno FROM DELETED
IF(@NEW>=1.1*@OLD)
INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade)
VALUES(@Sno,@Cno,@OLD,@NEW)
END
CREATE TABLE StudentInsertLog
(
Numbers INT
);
标准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:
CREATE TRIGGER Student_Count
ON Student
FOR INSERT
AS INSERT INTO StudentInsertLog(Numbers)
SELECT COUNT(*) FROM Student;
CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher /*触发事件是插入或更新操作*/
FOR EACH ROW /*行级触发器*/
BEGIN /*定义触发动作体,是PL/SQL过程块*/
IF (new.Job='教授') AND (new.Sal < 4000)
THEN new.Sal :=4000;
END IF;
END;
T-SQL:
CREATE TRIGGER Insert_Or_Update_Sal
ON Teacher
AFTER INSERT,UPDATE
AS
BEGIN DECLARE @Eno NUMERIC(4)
DECLARE @Ename CHAR(10)
DECLARE @Job CHAR(8)
DECLARE @Sal SMALLINT
SELECT @Sal=Sal FROM INSERTED
SELECT @Eno=Eno FROM Teacher
SELECT @Ename=Ename FROM Teacher
SELECT @Job=Job FROM Teacher
IF(@Sal<4000 AND @Job='教授')
UPDATE Teacher
SET Sal=4000
WHERE Sal<4000 AND Job='教授'
END
额没有截图结果啦!
七、存储过程
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;
ENDIF;
UPDATE Account SET total=total-amount
WHERE accountnum=outAccount; /* 修改转出账户余额,减去转出额 */
UPDATE Account SET total=total + amount
WHERE accountnum=inAccount; /* 修改转入账户余额,增加转入额 */
COMMIT; /* 提交转账事务 */
END;
(2)执行存储过程
CALL/PERFORM PROCEDURE 过程名([参数1,参数2,...]);
CALL PROCEDURE TRANSFER(01003815868,01003813828,10000);
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
触发器和存储过程好难写哦=.=