【數據庫】作業13——SQL練習8 - CHECK / CONSTRAINT / TRIGGER / PROCEDURE/ FUNCTION


1. 在SQLserver上運行,觀察運行效果,並把代碼寫到作業中。

2. 寫出自己的理解/收穫/心得體會(部分比較複雜的例題,建議增加測試方法和測試數據,舉一反三)。

 

作業原地址:作業

 

目錄

【5.1   實體完整性】

5.1.1   定義實體完整性

5.12   實體完整性檢查和違約處理

 

【5.2   參照完整性】

5.2.1   定義參照完整性

5.2.2   參照完整性檢查和違約處理

【5.3   用戶定義的完整性】

5.3.1   屬性上的約束條件

1.屬性上約束條件的定義

2.屬性上約束條件的檢查和違約處理

5.3.2   元組上的約束條件

1.元組上約束條件的定義

2.元組上約束條件的檢查和違約處理

5.4   完整性約束命名子句

1.完整性約束命名子句

2.修改表中的完整性限制

【5.7   觸發器】

5.7.1   定義觸發器

存儲過程

總結

 


 

【5.1   實體完整性】

 

5.1.1   定義實體完整性

 

對單屬性構成的碼有兩種說明方法,一種是定義爲列級約束條件,另一種是定義爲表級約束條件。

對多個屬性構成的碼只有一種說法,即定義爲表級約束條件。

 

【例5.1】將Student表中的Sno屬性定義爲碼。

 

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)                /*在表級定義主碼*/
    ); 

 

【例5.2】將SC表中的Sno、Cno屬性組定義爲碼。

 

CREATE TABLE SC
    (Sno CHAR(9) NOT NULL, 
     Cno CHAR(4) NOT NULL,  
     Grade SMALLINT,
     PRIMARY KEY (Sno,Cno)    /*只能在表級定義主碼*/
    ); 

 


 

5.12   實體完整性檢查和違約處理

 

用PRIMARY KEY 短語定義了關係的主碼後,每當用戶程序對基本表插入一條記錄或對主碼列進行更新操作時,實體完整性規則自動進行檢查。包括:

(1)檢查主碼值是否唯一,如果不唯一則拒絕插入或修改。

(2)檢查主碼的各個屬性是否爲空,只要有一個爲空就拒絕插入或修改。

 


 

【5.2   參照完整性】

 

5.2.1   定義參照完整性

 

關係模型的參照完整性在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.2.2   參照完整性檢查和違約處理

 

可能破壞參照完整性的情況及違約處理
被參照表(例如Student) 參照表(例如SC) 違約處理
可能破壞參照完整性 插入元組 拒絕
可能破壞參照完整性 修改外碼值 拒絕
刪除元組 可能破壞參照完整性 拒絕/級連刪除/設置爲空值
修改主碼值 可能破壞參照完整性 拒絕/級連刪除/設置爲空值

 

當不一致發生時,系統處理方式:

(1)拒絕(NO ACTION)執行

(2)級聯(CASCADE)操作

(3)設置爲空值

 

【例5.4】顯式說明參照完整性的違約處理示例。

 

CREATE TABLE SC
(Sno CHAR(9),
 Cno CHAR(4),
 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表中相應的元組*/
);

 


 

【5.3   用戶定義的完整性】

 

5.3.1   屬性上的約束條件

 

1.屬性上約束條件的定義

 

在CREATE TABLE 中定義屬性的同時,可以根據應用要求定義屬性上的約束條件,即屬性值限制,包括:

  • 列值非空(NOT NULL)
  • 列值唯一(UNIQUE)
  • 檢查列值是否滿足一個條件表達式(CHECK)

 

(1)不允許取空值

【例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),       /*在表級定義實體完整性,隱含了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,         /*Sname屬性不允許取空值*/
     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.屬性上約束條件的檢查和違約處理

當往表中插入元組或修改屬性的值時,關係數據庫管理系統將檢查屬性上的約束條件是否被滿足,如果不滿足則操作被拒絕執行。

 


 

5.3.2   元組上的約束條件

 

1.元組上約束條件的定義

 

【例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兩個屬性值之間的約束條件*/
    );

 

2.元組上約束條件的檢查和違約處理

 

當往表中插入元組或修改屬性的值時,關係數據庫管理系統將檢查元組上的約束條件是否被滿足,如果不滿足則操作被拒絕執行。

 


 

5.4   完整性約束命名子句

 

1.完整性約束命名子句

 

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

 

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

 

2.修改表中的完整性限制

 

可以使用ALER TBALE 語句修改表中的完整性限制。

 

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

 


 

【5.7   觸發器】

 

觸發器,是用戶定義在關係表上的一類由事件驅動的特殊過程。

 

5.7.1   定義觸發器

 

觸發器又叫做 事件-條件-動作 規則。

當特定的特殊事件發生時,對規則的條件進行檢查,如果條件成立則執行規則中的動作,否則不執行改動作。

GREATE TRIGGER 命令建立觸發器。

 

CREATE TRIGGER <觸發器名>
{BEFORE | AFTER} <觸發事件> ON <表名>
REFERENCING NEW|OLD ROW AS<變量>
FOR EACH  {ROW | STATEMENT}
[WHEN <觸發條件>]<觸發動作體>

 

【例5.21】當對錶SC的Grade屬性進行修改時,若分數增加了10%則將此次操作記錄到下面表中: SC_U(Sno,Cno,Oldgrade,Newgrade) 其中Oldgrade是修改前的分數,Newgrade是修改後的分數。

 

CREATE TRIGGER SC_T                /*SC_T是觸發器的名字*/	
AFTER UPDATE OF Grade ON SC        /*UPDATE OF Grade ON SC 是觸發條件*/
        /*AFTER 是出發的時機,表示當對SC的Grade屬性修改完後再出發下面的規則*/
REFERENCING
	 OLDROW AS OldTuple,
	 NEWROW AS NewTuple
FOR EACH ROW        /*行級觸發器,即每執行每一次Grade的更新,下面的規則就執行一次*/
WHEN (NewTuple.Grade>=1.1*OldTuple.Grade)        /*觸發條件,只有條件爲真時才執行*/
	INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade)        /*下面的INSERT操作*/
	VALUES(OldTuple.Sno,OldTuple.Cno,OldTuple.Grade,NewTuple.Grade)

 

【例5.22】將每次對錶Student的插入操作所增加的學生個數記錄到表StudentInsertLog中。

 

CREATE TRIGGER Student_Count
AFTER INSERT ON Student  	         /*指明觸發器激活的時間是在執行INSERT後*/
REFERENCING
 	NEW TABLE AS DELTA
FOR EACH STATEMENT
                        /*語句級觸發器,即執行完INSERT語句後下面的觸發動作體才執行一次*/
    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     /*BEFORE觸發事件*/
FOR EACH ROW        /*這是行級觸發器*/
BEGIN               /*定義觸發動作體,是PL/SQL過程塊*/
    IF(new.Job='教授') AND (new.Sal<4000)
                                    /*因爲是行級觸發器,可在過程體重*/
    THEN new.Sal :=4000;            /*使用插入或更新操作後的新值*/
    END IF;
END;                                /*觸發動作體結束*/

 


 

存儲過程

 

【例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;
  END IF;
  UPDATE Account SET total=total-amount WHERE accountnum=outAccount; 
    /*修改轉出賬戶餘額,減去轉出額 */
  UPDATE Account SET total=total + amount 
  WHERE accountnum=inAccount; /* 修改轉入賬戶餘額,增加轉入額 */
  COMMIT;                       	/*提交轉賬事務 */
END;

 

【例8.9】從賬戶01003815868轉10000元到01003813828賬戶中。

 

CALL PROCEDURE TRANSFER(01003813828,01003815868,10000`);

 


 

總結

 

這章稍微有點難了,感覺有點亂。還好老師已經發了博客,有參考也能多研究些。

 


完成時間:1h43min

          以上

                                         ————(2020.4.5)

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章