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

一、实体完整性

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、参照完整性检查和违约处理

参照完整性将两个表的相应元组联系起来了,因此,对被参照表和参照表进行增删改时可能破坏参照完整性,必须进行检查以保证这两个表的相容性
数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第1张图片
在这里插入图片描述

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不允许取空值,在列级不允许取空值的定义可不写*/
        .
        .
        .
);

(2)列值唯一
在这里插入图片描述

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

当改变一个值增加了10%时:数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第2张图片
在这里插入图片描述

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;

在这里插入图片描述
标准SQL:

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

额没有截图结果啦!


七、存储过程

在这里插入图片描述
(1)创建存储过程

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

数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION_第3张图片
建立存储过程

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

在这里插入图片描述102账户转出50到101账户!

触发器和存储过程好难写哦=.=

你可能感兴趣的:(数据库作业13:SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION)