Table of Contents
4.4.5 參照完整性 (referential integrity)
第四章 中級SQL
4.1 連接表達式
4.1.1 連接條件
- natural join子句: 自然連接,在兩個關係都包括的屬性上要取值匹配
- join...using子句:是自然連接的一種形式,只需要在指定屬性上的取值匹配。
- on 條件:允許在參與連接的關係上設置通用的謂詞,例如:
select * from student join takes on student.ID = takes.ID;
-- 等價於
select * from student natural join takes;
-- 等價於
select * from student, takes where student.ID = takes.ID;
4.1.2 外連接 outer join
有三種形式的外連接(outer join):
- 左外連接(left outer join): 只保留出現在左外連接運算之前(左邊)的關係中的元組
- 右外連接(right outer join): 只保留出現在右外連接運算之後(右邊)的關係中的元組
- 全外連接(full outer join): 保留出現在兩個關係中的元組
內連接(inner join):不保留未匹配元組的連接運算被稱作內連接運算。
-- 不指定outer時,默認是內連接
select * from student (inner) join takes using (ID);
-- 左外連接
select * from student natural left outer join takes;
-- 右外連接
select * from student natrual right outer join takes;
-- 全外鏈接
select * from student natural full outer join takes;
-- on子句可以與外連接一起用
select * from student left outer join takes on student.ID = takes.ID;
--等價於
select * from student left outer join on true where student.ID = takes.ID;
4.1.2 連接類型和條件
在連接時,可以將任意的連接類型和任意的連接條件相組合。
4.2 視圖
視圖(view):視圖可以向用戶隱藏特定的數據;不進行預先計算和存儲,在使用時通過執行查詢被計算出來。
虛關係:虛關係並不預先計算並存儲,而是在使用時通過執行查詢被計算出來。
4.2.1 視圖定義
-- create view v as <query expression>; e.g:
create view faculty as select ID, name, dept_name from instructor;
4.2.2 SQL查詢中使用視圖
在任何時刻,視圖關係中的元組集是該時刻視圖定義中的查詢表達式的計算結果。
通常來說,當我們定義一個視圖時,數據庫系統存儲視圖的定義本身,而不存儲定義該視圖的查詢表達式的執行結果。
一旦視圖關係出現在查詢中,它就被已存儲的查詢表達式代替。因此,無論何時執行這個視圖,視圖關係都會被重新計算。
4.2.3 物化視圖
物化視圖(materialized view): 如果用於定義視圖的實際關係發生改變,視圖也跟着修改。這樣的視圖稱爲物化視圖。
物化視圖維護(materialized view maintenance)/視圖維護(view maintenance):保持物化視圖一直在最新狀態的過程稱爲物化視圖維護。
物化視圖維護方式:
1. 數據庫系統在底層關係變化時,總是立即更新物化視圖的內容;
2. 週期性更新物化視圖;
4.2.4 視圖更新
一般來說,除了一些有限的情況之外,不允許對視圖關係進行修改。不同數據庫系統指定了不同的條件以允許對視圖關係進行修改。
(注意:此處說的對視圖進行更新,是指對視圖進行更新,並要求同時對視圖來源的底層關係進行更新)
一般來說,如果滿足下列條件,我們就說視圖是可以更新的:
- from子句中只有一個數據庫關係
- select子句中只包括關係的屬性名,不包含任何表達式、聚集或distinct聲明
- 任何沒有出現在select子句中的屬性都可以取空值,即:這些屬性沒有not null約束,並且也不構成主碼的一部分
- 查詢中不含有group by或having子句
即便視圖是可更新的,也會存在其他的問題。如:插入一條數據,但是該數據不滿足視圖的查詢條件,那麼這條數據也不會出現在視圖中。
此時,可以再視圖定義的末尾加上with check option來拒絕這類更新。
4.3 事務
事務(transaction)由查詢和(或)更新語句的序列組成。
- commit work:提交當前事務,也就是該事務所做的更新在數據庫中持久保存。在事務提交之後,一個新的事務自動開始
- rollback work:回滾當前事務,即撤銷該事務中的所有SQL語句對數據庫的更新。這樣,數據庫就恢復到執行該事務第一條語句之前的狀態
一旦事務進行了commit,它的影響就不能被rollback了。
事務具有原子性(atomic):原子性也就是不可分割性,即:事務的所有步驟要麼都成功並提交,要麼都不成功進行回滾。
begin atomic...end可以用來創建一個由多條語句組成的事務。
4.4 完整性約束
完整性約束保證授權用戶對數據庫所做的修改不會破壞數據的一致性。完整性約束防止的是對數據的意外破壞。
完整性約束通常被看成是數據庫模式設計過程的一部分,它作爲用於創建關係的create table的命令的一部分被聲明。
也可以通過alter table table-name add constraint命令追加約束。
4.4.1 - 4.4.4 單個關係上的約束
- not null:禁止被修飾屬性上出現空值
name varchar(20) not null budget numberic(10,2) not null
- unique: 聲明候選碼,即在關係中沒有兩個元組能夠在所有列出的屬性上取值相同
unique(A1,A2,...,An)
- check (<謂詞>):指定關係中的所有元組都要滿足給定謂詞
check(budget>0) check(semester in ('Fall','Winter','Spring','Summer'))
4.4.5 參照完整性 (referential integrity)
參照完整性:保證一個關係中給定屬性集上的取值也在另一關係的特定屬性集 的取值中出現。
外碼(foreign key):令關係r1和r2的屬性集分別爲R1和R2,主碼分別爲K1和K2.如果要求對r2中任意元組t2,均存在r1中元組t1,使得t1.K1=t2.alpha, 我們稱R2的子集alpha爲參照關係r1中K1的外碼。
參照完整性約束(referential integrity constraint)/ 子集依賴(subset dependency):在上述情況中,要求r2中alpha上的取值集合必須是r1中K1上的取值的集合的子集。但是與外碼不同,參照完整性約束不要求K1是r1的主碼,、。
--定義外碼約束,要求被參照屬性是被參照關係的主碼
foreign key (dept_name) references department
-- 定義參照完整性約束,不要求被參照屬性是被參照關係的候選碼
dept_name varchar(20) references department
/*注意: 當違反參照完整性時,通常的處理是拒絕執行該操作。 但是使用foreign key是可以明確指明若違反完整性約束,可以採取一些步驟來修改參照關係中的元組來回復完整性操作,而不是拒絕操作*/
-- on delete cascade子句規定如果刪除department中的元組導致完整性約束被破壞,則級聯刪除course
create table course( ... foreign key(dept_name) references department on delete cascade/set null/set default on update cascade, ... )
4.4.6 事務中對完整性約束的違反
默認情況下,執行每個語句時都會立即檢查完整性約束。
initially deferred子句:該子句加入到約束聲明中,可以實現完整性約束不是在事務的中間步驟上檢查,而是在事務結束的時候時候檢查。
set constraints constraint-list deferred: 可以聲明事務延遲檢查給定約束到事物結束時執行。
舉例:
person(name,spouse),其中name爲主碼,spouse爲外碼。 約束要求spouse必須爲person中出現的name。 插入A-B,A和B爲夫妻關係,則不管先插入A還是先插入B都會違反外碼約束。
4.4.7 複雜check條件與斷言
check子句中的謂詞可以是包含子查詢。
複雜check條件在確保數據完整性上十分有用,但是其檢測開銷會很大。
斷言(Assertion):一個斷言就是一個謂詞,他表達了我們希望數據庫滿足的一個條件。域約束和參照完整性約束是斷言的特殊形式。
create assertion <assertion-name> check <predicate>;
例如:
/*斷言:對於student關係中的每個元組,他在屬性tot_cred上的取值必須等於該生所成功修完課程的學分總和*/
create assertion credits_earned_constraint
check (not exists (
select ID from student where tot_cred<>
(select sum(credits) from takes natural join course
where student.ID = takes.ID and grade is not null and grade<>'F')));
4.5 SQL的數據類型與模式
4.5.1 SQL的日期和時間類型
- date:日曆時間,包括年(四位)、月、日。
- time:一天中的時間,包括小時、分、秒。可以用變量time(p)來指定秒的小數點後的數字位數。
- timestamp:date和time的組合。可以用變量timestamp(p)來指定秒的小數點後的數字位數。如果指定with timezone,則時區信息也會被存儲。
date '2001-04-05' time '09:30:00' timestamp: '2001-04-05 10:29:01.45'
cast e as t: 可以將一個字符串e轉換爲日期或時間類型t,類型t可以是date,time和timestamp中的一種。要求字符串必須符合正確的格式。
extract (field from d): 從date或time值d中提取出單獨的域。域包括: year, month, day, hour, minute, second; timezone_hour, timezone_minute
current_date: 返回當前日期
current_time:返回當前時間(帶有時間)
localtime:返回當前本地時間(不帶時區)
時間戳:current_timestamp(帶時區),localtimestamp(本地日期和時間,不帶時區)
4.5.2 默認值
default關鍵字用於指定默認值。
create table student(
ID varchar(5) ,
name varchar(20) not null,
dept_name varchar(20),
tot_cred numberic(3,0) default 0,
primary key (ID)
);
4.5.3 創建索引
在關係屬性上所創建的索引(index)是一種數據結構。
它允許數據庫系統高效的查詢關係中那些在索引屬性上取給定值的元組,而不用掃描關係中的所有元組。
如果用戶提交的SQL查詢可以從索引的使用種獲益,那麼SQL查詢處理器會自動使用索引。
// 在student上根據屬性ID創建索引 create index studentID_index on student(ID);
4.5.4 大對象類型
clob:字符數據的大對象數據類型
blob:二進制數據的大對象數據類型
(lob代表 Large OBject)
注意:把整個大對象放入內存中是非常低效和不現實的。一個應用通常用一個SQL查詢來檢索出一個大對象的”定位器“,然後再宿主語言中利用定位器來操作對象。
book_review clob(10KB) image blob(10MB) movie blob(2GB)
4.5.5 用戶定義的類型
SQL支持兩種形式的用戶定義數據類型:
- 結構化數據類型(structured data type): 允許創建具有嵌套記錄結構、數組和多重集的複雜數據類型。
- 獨特類型(distinct type):(注意,不同數據庫支持的內容不同)
-- 會進行強類型檢查,Pounds類型的值不能賦給Dollars類型的屬性
create type Dollars as numberic(12, 2) final; create type Pounds as numberic(12, 2) final;
-- 將一種類型的值域轉爲另一種類型
cast (department.budget to numberic(12,2))
--刪除類型和修改類型 drop type alter type
--域domain:在基本類型上施加完整性約束;domain也可以作爲屬性類型
create domain DDollars as numberic(12,2) not null;
--聲明來自該域的任何變量都要滿足給定謂詞
create domain YearlySalary numberic(8,2) constraint slary_value_test check(value>=290000.00);
--類型和域的兩大差別:
/* 1. 在域上面可以聲明約束,也可以爲域類型變量定義默認值;但是類型定義上不能聲明約束或默認值 2. 域並不是強類型的。因此一個域類型的值可以被賦給另一個域類型,只要它們的基本類型是相容的 */
4.5.6 create table的擴展
創建與現有的某個表的模式相同的表:
// 創建一個與instructor具有相同模式的新表
create table temp_instructor like instructor;
with data子句:
列的名稱和數據類型是從查詢結果中推導出來的。
-- SQL:2003標準定義,省略with data時,只會創建表,但是不會載入數據
-- 但是很多數據庫的實現都支持自動載入,即使省略with data
with data create table t1 as (select * from instructor where dept_name='Music')
-- 不同數據庫實現的類似的語法 create table ... as create table ... like
4.5.7 模式、目錄與環境
文件系統的目錄:/users/avi/db-book/chapter3.tex
當代數據庫系統採取三層結構的關係命名機制:頂層由目錄(catalog)構成;每個目錄都可以包含模式(schema);關係和視圖都包含在模式中。
用戶操作數據庫的過程:
- 連接數據庫:此時用戶需要提供用戶名和密碼。
- 通常情況下,每個用戶都有一個默認的目錄和模式,這個組合對用戶來說是唯一的。
- 當用戶連接到數據庫系統時,將爲該連接設置好默認的目錄和模式。
爲了標識一個關係,必須使用一個名字,它由三部分組成:
catalog5.univ_schema.course
目錄.模式.關係名
其中目錄部分被認爲是連接時的默認目錄時,可以省略。
當有多個目錄和模式存在時,不同應用和不同用戶可以獨立工作而不必擔心命名衝突。
一個應用的不同版本可以再同一個數據庫系統上運行。
SQL環境:默認目錄和模式是爲每個連接建立的SQL環境的一部分。SQL環境還包括用戶標識(也稱授權標識)。
所有通常的SQL語句,包括DDL和DML,都在一個模式的環境中運行。
--創建和刪除模式
create schema drop schema
4.6 授權
權限(privilege)
- 對數據的授權包括:
- 授權讀取數據
- 授權插入新數據
- 授權更新數據
- 授權刪除數據
當用戶提交更新或查詢時,SQL執行先基於用戶曾獲得的權限檢查此查詢或更新是否是授權過的。如果沒有經過授權,那麼將拒絕執行。
- 對模式的授權:
- 允許用戶創建、修改和刪除關係
- 權限轉授的權利:
- 允許用戶給其他用戶授權、或撤銷授權
最大的授權形式是被授予數據庫管理員權限。它可以授權新用戶、重構數據庫等。
4.6.1 權限的授予與收回
SQL標準包括select, insert, update, 和delete權限。
- select: 允許讀取關係中的數組
- insert:允許插入新數據,但是不允許更新已有數據
- 也可以指定屬性列表,對關係的操作只能針對這些屬性,系統將其他屬性設置爲默認值或null。
- update:允許更新數據。
- 允許用戶修改關係中的任意元組
- 可以授予關係上的所有屬性,也可以只授予到某些屬性。
- delete: 允許刪除元組
授予權限:
grant <權限列表> on <關係名或視圖名> to <用戶/角色列表>
-- 授予Amit, Satoshi對department進行查詢的權限
grant select on department to Amit, Satoshi
-- 授予Amit 更新 department budget屬性;
-- 省略屬性列表代表對所有屬性都有更新權限
grant update(budget) on department to Amit
-- 用戶名public值系統的所有當前用戶和未來用戶
注意:SQL允許對整個關係,或者關係的屬性進行授權,但是不允許對一個關係的指定元組進行授權。
收回權限:revoke
revoke<權限列表> on <關係名或視圖名> from <用戶/角色列表>
-- 收回授權
revoke select on department from Amit;
revoke update(budget) on department from Amit;
4.6.2 角色
角色(Role):在數據庫中創建一個角色集,可以給角色授予權限。每個數據庫用戶被授予一組他有權扮演的角色(也可以是空的)。
-- 創建角色
create role role-name;
-- 給角色授權
grant select on <table/view-name> to <role-name>;
-- 授予用戶角色
grant <role-name> to <user-name>
-- 授予角色角色
grant <role-name A> to <role-name B>
一個用戶或者一個角色的權限包括:
- 直接授予該用戶/角色的權限
- 所有授予給用戶/角色所擁有的角色的權限
4.6.3 視圖的授權
創建視圖的用戶不會默認獲得該視圖上的所有權限。他得到的權限不會超過他已有權限的額外授權。
例如:如果一個創建視圖的用戶,在用來定義視圖的關係上沒有update權限的話,那麼它也不能得到視圖上的update權限。
如果用戶創建一個視圖,而此用戶在該視圖上不能得到任何權限,那麼該創建請求會被拒絕。
視圖的創建者必須在視圖參考關係上具有select權限。
在函數或者過程上也可以授予execute權限,以允許用戶執行函數或者過程。
4.6.4 模式的授權
SQL標準爲數據庫模式指定了一種基本的授權規則:只有模式的擁有者才能夠執行對模式的任何修改,如創建和刪除關係、增加或刪除屬性、增加或者刪除索引。
SQL提供了一種references權限,允許用戶在創建關係時聲明外碼。
references權限授予:
-- 允許用戶Mariano創建這樣的關係,它能夠參照department關係的碼dept_name
grant references (dept_name) on department to Mariano;
4.6.5 權限的轉移
獲得某些形式權限的用戶可能被允許將此授權傳遞給其他用戶。
默認方式下,被授予的用戶/角色無權把得到的權限再授予給另外的角色/用戶。
但是,可以在授權時指定是否允許接受者把權限傳遞給其他用戶(with grant option);
-- 授予Ami select權限,並允許Ami把select權限授予給其他用戶
grant select on department to Ami with grant option;
授權圖:授權圖可以指定一個用戶到另一個用戶的傳遞。該圖中的頂點是用戶,根節點是DBA(數據庫管理員)。
用戶具有權限的充分必要條件:當且僅當存在從授權圖的根到代表該用戶頂點的路徑。
4.6.6 權限的收回
級聯收回:從一個用戶/角色那裏收回權限可能會導致其他用戶/角色也失去該權限,這一行爲稱爲級聯收回。
例如:從U1出收回權限,由於U4是從U1那裏獲取到的權限,因此U4的權限也會被收回。
一些狡猾的用戶可能企圖通過相互授權來破壞權限回收規則。例如,U1授權給U2,U2再授權給U1。但是若DBA收回U1的權限,那麼U1和U2的權限都不會被保留,因爲他們都沒有到根的路徑。
對大多數數據庫系統,級聯收回是默認的行爲。
使用revoke可以聲明restrict來防止級聯收回。
-- 此時,如果存在級聯收回,則系統返回一個錯誤,且不執行收權動作
revoke select on department from Ami restrict;
-- 指定級聯收回(默認情況也是cascade,可以省略)
revoke select on department from Ami cascade;
-- 收回grant option權限
revoke grant option for select on department from Ami restrict;
級聯收回在許多情況下是不合適的。
比如:Satoshi具有dean角色,他將instructor角色授予Ami,後來Satoshi離開了大學,dean角色被收回。那麼如果Ami繼續在該大學作爲教職工,那麼instructor角色不應該被收回!!!
針對這種情況,SQL允許權限由一個角色賦予,而不是由用戶來授予。
// 默認情況下,一個會話所關聯的當前角色是空的(特殊情況除外) // 一個會話所關聯的角色可以通過set role role-name來設定 // 要求指定的角色必須已經授權給當前用戶,不然會執行失敗 set role role-name; // 如果當前角色不爲空的話,可以在授予權限的時候 設置授予該權限的是當前用戶的角色而不是用戶本身 grant instructor to Ami granted by current_role;
總結
- SQL支持:內連接、外連接(左外連接,右外連接,全外連接)
- 視圖關係可以定義爲包含查詢結果的關係。視圖可以隱藏不必要的信息,可以把信息從多個關係收集到一個單一的視圖中
- 事務是一個查詢和更新的序列,他們共同執行某項任務。事務可以被提交或者回滾。當一個事務被回滾時,該事務執行的所有更新所帶來的影響將被撤銷。
- 完整性約束保證授權用戶對數據庫所做的改變不會導致數據一致性的破壞
- 參照完整性約束保證出現在一個關係的給定屬性集上的值同樣出現在另一個關係的特定屬性集上
- 域約束指定了在一個屬性上可能取值的集合。這種約束也可以禁止在特定屬性集上使用空值。
- 斷言是描述性表達式,它指定了我們要求總是爲真的謂詞
- SQL數據定義語言提供對定義諸如date和time那樣的固有域類型以及用戶定義域類型的支持
- 通過SQL授權機制,可以按照在數據庫中不同數據值上數據庫用戶所允許的訪問類型對他們進行區分。
- 獲得了某種形式授權的用戶可能允許將此授權傳遞給其他用戶。但是,對於權限怎樣在用戶間傳遞我們必須小心,以保證這樣的權限再將來的某個時候可以被收回
- 角色有助於根據用戶在組織機構中所扮演的角色,把一組權限分配給用戶。