SQL入门(3):定义约束/断言assertion/触发器trigger
本文介紹數(shù)據(jù)庫的完整性
完整性控制程序: 指定規(guī)則,檢查規(guī)則 (規(guī)則就是約束條件)
動態(tài)約束 intergrity constraint::=(O,P,A,R)
O : 數(shù)據(jù)集合, 約束的對象 ?: 列, 多列的元組集合
P: 謂詞條件: 什么樣的約束?
A: 觸發(fā)條件: 什么時候檢查?
R: 響應(yīng)動作: 不滿足怎么辦?
按照約束對象分類:
(1)域完整性約束條件: 施加在某一列上, 比如sage<25 and sage<40
(2)關(guān)系完整性約束條件: 施加在表上, 涉及多列, 2<=hours/credit<=16
按照約束來源分類:
(1)結(jié)構(gòu)約束: 主鍵約束, 外鍵約束,是否允許空值等 primary key, foreign key, not null
(2) 內(nèi)容約束:? 取值范圍, check(sage<25 and sage<40)
按照約束狀態(tài)分類:
(1) 靜態(tài)約束: 要求DB在任何時候都要滿足的約束
(2) 動態(tài)動態(tài): DB改變狀態(tài)時要滿足的約束, 例如salary 只能加不能減, 不能由1000改為500.---> 觸發(fā)器
SQL支持如下幾種約束:?
靜態(tài)約束中的列完整性 與表完整性,??動態(tài)約束中的觸發(fā)器
(一) 靜態(tài)約束
實現(xiàn): create table
(1) col_constr 列約束 (一種域約束類型, 對單一列的值進行約束)
not null 列值非空
primary key 主鍵
not null + unique 就是非空+唯一性 ,實際上就是一個主鍵
check (search_condition) 列值滿足的條件,?
references tablename(colname) , colname 是tablename 的主鍵
on delete[ cascade| set null], 則刪除被引用表的某一列v值時, 要將本表該列
值為v 的記錄刪除 或者 列值更新為null, 缺省為無操作.?
例: 創(chuàng)建一個表 student
create table student (sno char(8) not null unique, sname char(10), --not null unique 表示主鍵 ssex char(2) constraint ctssex check(ssex='男' or ssex='女'), -- ctssex 是約束constraint 的名字. 之后可以單獨處理 sage integer check(sage>=1 and sage<150), -- 沒有定義約束名, 則之后不能單獨處理 dno char(2) references dept(dno) on delete cascade, -- dno 在dept表中 是主鍵, sclass char(6));on delete cascade 表示如果dept表中的某個'01'系被刪除了,
那么在student 表中該系所有學(xué)生的dept 值為null, 如果沒有加這個, 那么dept表中的刪除操作對
student表沒有影響.
create table course (cno char(3), cname char(10), chours integer, credit float(1) constraint ctcredit check(credit>=1.0 and credit <=6.0), tno char(3) references teacher(tno) on delete cascade); -- 或者通過alter alter table course add constraint cs_tno foreign key(tno) references teacher(tno) on delete cascade; -- 移除約束 alter table course drop constraint cs_tno;補充: unique 和not null?
create table tbl1(name1 varchar(10), num1 varchar(10), constraint cs_num1 unique(num1)); -- 或者 create table tbl1(name1 varchar(10), num1 varchar(10) unique); -- 之后再添 alter table tbl1 add constraint cs_num1 unique(num1); alter table tbl1 drop constraint ; -- 非空約束 create table tbl1(name1 varchar(10), num1 varchar(10) not null); -- 新增非空約束 alter table tbl1 modify num1 not null; -- 刪除非空約束 不是用drop alter table tbl1 modify num1 null;?
(2)?table_constr 表約束, 用于多列或者元組的值進行約束
create table student ( sno char(5) not null unique,sname char(5), ssex char(2) constraint ctssex check(ssex='男' or ssex='女') , sage integer check(sage>1 and sage<150). dno char(3) references dept (dno) on delete cascade, sclass char(5),primary key(sno));--primary key(sno) 可以放在sno 這一列的后面, 也可以放在最后這里,?看成是表約束
create table course (cno char(3), cname char(10), chours integer, credit float(1) constraint ctcredit check(credit>=1.0 and credit <=6.0), tno char(3) references teacher(tno) on delete cascade, primary key (cno), constraint ctcc check(chours/credit=12)); -- 嚴格約束12課時對應(yīng)1個學(xué)分 create table sc(sno char(5), cno char(3), score float(1) constraint ctscore check(score>=0.0 and score<=100.0), foreign key(sno) references student(sno) on delete cascade, foreign key(cno) references course(cno) on delete cascade);注意: check 后面的條件可以是select from where 語句
create table sc(sno char(5) check (sno in (select sno from student)),cno char(3), check(cno in (select cno from course)), --相當(dāng)于外鍵 score float(1) constraint ctscore check(score>=0.0 and score<=100.0);
注意: create table 中的約束條件 可以在后面根據(jù)需要進行撤銷 ,也可以追加約束
alter? table? tablename +?
add 追加約束,? 也可以增加新的一列
drop 刪除一列的約束,或者刪除一列,
modify 修改
alter table sc drop constraint ctscore; -- 撤銷對score的約束ctscore; alter table sc modify ( score float(1) constraint nctscore check(score>0.0 and score<=150.0));-- 修改約束 alter table sc add ( score float(1) constraint nctscore check(score>0.0 and score<=150.0));
-- 增加約束
(3) 斷言 assertion?
一個斷言就是一個謂詞表達式, 它表達了希望數(shù)據(jù)庫總能滿足的條件,?表約束與 列約束就是一些特殊的斷言.
還有復(fù)雜的斷言??create assertion [assertion name] check [predicate]
那么之后數(shù)據(jù)庫的每一次更新去判斷是否違反該斷言, 斷言測試增加了數(shù)據(jù)庫維護的負擔(dān), 沒事不要使用!!?
例如: 每位教師同一時間段不能在兩個不同的地方上課.
實例1: 已知下列4張表
borrower(client_name,loan_num) 客戶以及他的貸款
account(account_num,balance) 賬戶和余額
depositor(account_num, client_name) 賬戶與客戶名
loan(loan_num, amount)? 每一筆貸款
現(xiàn)在規(guī)定: 每一筆貸款 , 要求至少這個借款者的賬戶中有最低余額500元.
create assertion balance_cst check (not exists (select * from loan where not exists (select * from borrower b, depositor d, account a where loan.loan_num=b.loan_num and b.client_name=d.client_name and a.account_num=d.account_num and a.balance>=500)));實例2: 現(xiàn)有3張表
account(branch_name, account_num, balance) 分行 賬戶 與 余額
loan(branch_name,loan_num,amount) 分行的每一筆貸款
branch(branch_name,..) 分行信息
每一個分行的貸款總量要小于該分行所有賬戶的余額總額 (不存在某一個分行 它的貸款額大于余額)
create assertion sum_cst check (not exists (select * from branch where (select sum(amount) from loan where loan.branch_name=branch.branch_name) >= (select sum(balance) from account where account.branch_name=branch.branch_name)));?(二) 動態(tài)約束
以上 create table 中的表約束與列約束?是靜態(tài)約束,?下面介紹動態(tài)約束--> 觸發(fā)器 trigger
動態(tài)約束是一種過程完整性的約束, 相比之下, 之前的create table 的約束是非過程性約束
動態(tài)約束是一個程序, 該程序可以在特定的時刻被自動觸發(fā)執(zhí)行: 比如在一次更新之前,?
或者一次更新之后的執(zhí)行.?
動態(tài)約束 intergrity constraint::=(O,P,A,R), O P A R 都需要定義, 再來回顧下?
O : 數(shù)據(jù)集合, 約束的對象 ?: 列, 多列的元組集合
P: 謂詞條件: 什么樣的約束?
A: 觸發(fā)條件: 什么時候檢查?
R: 響應(yīng)動作: 不滿足怎么辦?
以下是Oracle 的觸發(fā)器的語法例子, 在SQL server中 語法略有差別, 但是思路一致. ..
?創(chuàng)建觸發(fā)器的基本語法:
create trigger? trigger_name
before| after? [insert | delete|update] [of colname]?on tablename?
for each row| for each statement
when [search_condition]
[statement]
[begin? atomic statement; ... end;]? --多個條件
注意: row , as 可以省略!?
實例(1):? 當(dāng)teacher表更新元組時, 控制其工資只能漲不能跌
create trigger teacher_sal-- 觸發(fā)器名字 before update of salary on teacher -- 作用在什么表的什么列 referencing new x, old y -- 定義更新前后的值 for each row when(x.salary<y.salary) -- 對每一條記錄都要檢查, begin --如果違反則執(zhí)行raise_application_error(-20003,'invalid salary on update');-- Oracle的錯誤處理函數(shù), 提示無效更新end;實例(2) : student(sno, sname, sumcourse), sumcourse 表示該同學(xué)已經(jīng)學(xué)習(xí)的課程門數(shù),
初始值是0, 以后每修一門課都要對其+1, 設(shè)計一個觸發(fā)器自動完成這個功能.
create trigger sumc after insert on sc -- 對于sc 的新增信息 作出反應(yīng) referencing new row newI-- 定義更新后的行=newi for each rowbegin -- 執(zhí)行操作update student set sumsourse=sumcourse+1 where sno=:newi.sno; -- 這條記錄(行)對應(yīng)的學(xué)號end;?
實例(3) :student(sno, sname, sage,ssex,scalss) 中某一個學(xué)生變動其主碼sno
,則在sc 表中該同學(xué)的學(xué)號也要相應(yīng)改變
create trigger upd_sno after update of sno on student --指明更新的地方 referencing old oldi, new newi for each rowbeginupdate sc set sno=newi.sno where sno=: oldi.sno;end;實例(4)?:student(sno, sname, sumcourse)中刪除某一個學(xué)生sno時, 在sc 中該學(xué)生的
選課記錄也要刪除
create trigger del_sno after delete on student referencing old oldi for each rowbegindelete sc where sno=:oldi.sno;end;實例(5) :?student(sno, sname, sumcourse)中刪除某一個學(xué)生sno時, 在sc 中該學(xué)生的sno設(shè)置為null
create trigger del_sno after delete on student referencing old oldi for each rowbeginupdate sc set sno=null where sno=:oldi.sno;end;實例(6)?:假設(shè)有兩張表, dept(dno,dname,dean) ,該表字段是系號 系名 系主任名, 以及
teacher(tno,tname,dno,salary) .?現(xiàn)在需要控制 在對dept 的dean 做更新的時候,
必須滿足dean 的工資是同一系里最高的,?否則更新報錯.
create trigger dean_sal before update of dean on dept -- 對dept 的dean 做更新的時候 referencing old oldi , new newi -- 更新前后的新 舊定義for each row when(dean not in (select tname from teacher where dno=:newi.dno and salary> = all(select salary from teacher where dno=:newi.dno )))-- 同系教師工資begin -- 不滿足條件時raise_application_error(-20003,'invalid dean on update');end;
?
轉(zhuǎn)載于:https://www.cnblogs.com/xuying-fall/p/9408348.html
總結(jié)
以上是生活随笔為你收集整理的SQL入门(3):定义约束/断言assertion/触发器trigger的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java高并发程序设计(六)--线程池(
- 下一篇: mysql text与blog的区别