SQL练习8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION

一、实体完整性定义
[例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)    /*只能在表级定义主码*/
       ); 

插入或更新操作时,DBMS按照实体完整性规则自动进行检查。
检查主码值是否唯一,如果不唯一则拒绝插入或修改
检查主码的各个属性是否为空,只要有一个为空就拒绝插入或修改。
二、参照完整性定义
例如,关系SC中(Sno,Cno)是主码。Sno,Cno分别参照Student表的主码和Course表的主码
[例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)FOREIGN KEY (Sno) REFERENCES Student(Sno) 
	ON DELETE CASCADE        /*级联删除SC表中相应的元组*/
         ON UPDATE CASCADE,      /*级联更新SC表中相应的元组*/
       FOREIGN KEY (Cno) REFERENCES Course(Cno)	                    
         ON DELETE NO ACTION 	
             /*当删除course 表中的元组造成了与SC表不一致时拒绝删除*/
         ON UPDATE CASCADE   
  	  /*当更新course表中的cno时,级联更新SC表中相应的元组*/
       );

三、用户定义的完整性
1、属性上的约束条件
(1)不允许取空值
[例5.5] 在定义SC表时,说明Sno、Cno、Grade属性不允许取空值。

  CREATE TABLE SC
    (  Sno CHAR(9)  NOT NULL,	
       Cno CHAR(4)  NOT NULL,	
       Grade  SMALLINT NOT NULL,	
       PRIMARY KEY (Sno, Cno),/* 如果在表级定义实体完整性,隐含了Sno,Cno不允许取空值,则在  
         列级不允许取空值的定义 可以不写 * /
     ); 

(2)列值唯一
[例5.6]建立部门表DEPT,要求部门名称Dname列取值唯一,部门编号Deptno列为主码

CREATE TABLE DEPT
    (   Deptno  NUMERIC(2),
        Dname  CHAR(9)  UNIQUE NOT NULL/*要求Dname列值唯一, 并且不能取空值*/
        Location  CHAR(10),
        PRIMARY KEY (Deptno)
     );

在这里插入图片描述
3)用CHECK短语指定列值应该满足的条件

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

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

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

插入元组或修改属性的值时,关系数据库管理系统检查属性上的约束条件是否被满足;如果不满足则操作被拒绝执行
2、元组上的约束条件
在CREATE TABLE时可以用CHECK短语定义元组上的约束条件,即元组级的限制
[例5.9]当学生的性别是男时,其名字不能以Ms.打头。

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两个属性值之间的约束条件*/
      );

这个例子可以多测试几遍,例如把女生的名字设成Ms.或者把男生的名字设成Ms.
四、完整性约束命名子句

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

<完整性约束条件>包括NOT NULL、UNIQUE、PRIMARY KEY短语、FOREIGN KEY短语、CHECK短语等
[例5.10]建立学生登记表Student,要求学号在90000~99999之间,姓名不能取空值,年龄小于30,性别只能是“男”或“女”。

 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四个列级约束。当去掉这些约束的时候,给这些约数起的名字就起作用了。
[例5.11]建立教师表TEACHER,要求每个教师的应发工资不低于3000元。
应发工资是工资列Sal与扣除项Deduct之和。

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

在这里插入图片描述
使用ALTER TABLE语句修改表中的完整性限制
[例5.12]去掉例5.10 Student表中对性别的限制。

ALTER TABLE Student 
    DROP CONSTRAINT C4;

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

五、触发器
触发器(Trigger)

①、任何用户对表的增、删、改操作均由服务器自动激活相应的触发器;
②、触发器可以实施更为复杂的检查和操作,具有更精细和更强大的数据控制能力

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

触发器类型:
行级触发器(FOR EACH ROW)
语句级触发器(FOR EACH STATEMENT)
[例5.21]当对表SC的Grade属性进行修改时,若分数增加了10%则将此次操作记录到下面表中:
SC_U(Sno,Cno,Oldgrade,Newgrade)
其中Oldgrade是修改前的分数,Newgrade是修改后的分数。

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(4)
IF(UPDATE(Grade))
	BEGIN
	select @OLD =Grade FROM DELETED
	select @NEW =Grade FROM INSERTED
	select @SNO =Sno FROM SC
	select @CNO =Cno FROM SC
	IF(@NEW>=1.1*@OLD)
	INSERT INTO SC_U(Sno,Cno,Oldgrade,Newgrade)
	VALUES (@SNO,@CNO,@OLD,@NEW)
END

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

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

[例5.23] 定义一个BEFORE行级触发器,为教师表Teacher定义完整性规则“教授的工资不得低于4000元,如果低于4000元,自动改为4000元”。

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;    

8.8存储过程和函数
(1)创建存储过程
CREATE OR REPLACE PROCEDURE 过程名([参数1,参数2,…]) AS <过程化SQL块>;
[例8.8] 利用存储过程来实现下面的应用:从账户1转指定数额的款项到账户2中。

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,…]);
[例8.9] 从账户01003815868转10000元到01003813828账户中。

CALL PROCEDURE       TRANSFER(01003813828,01003815868,10000);

(3)修改存储过程

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

(4)删除存储过程

DROP  PROCEDURE 过程名()

对于视图我有一点不明白的地方,按照要求做了总是报错,我在研究研究

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值