第3章 SQL
SQL查詢語言概覽
SQL語言主要有以下的幾個部分:
- 數據定義語言(Data Definition Language,DDL):SQL DDL提供定義關係模式,刪除關係以及刪除關係模式的命令。
- 數據操縱語言(Data Manipulation Language,DML):SQL DML提供從數據庫中查詢信息,以及在數據庫中插入元組、刪除元組和修改元組的能力。
- 完整性(Integrity):SQL DDL包括定義完整性約束的命令,保存在數據庫匯中的數據必須滿足所有定義的完整性約束。
- 視圖定義(View definition):SQL DDL包括定義視圖的命令。
- 事務控制(transaction control):SQL包括定義事務的開始和結束的命令。
- 嵌入式SQL和動態SQL(embedded SQL and dynamic SQL):嵌入式和動態SQL定義SQL語句如何嵌入到通用編程語句,例如C、C++和Java中。
- 授權(authorization):SQL DDL包括定義對關係和視圖的訪問權限的命令。
SQL數據定義
定義的信息包括:
- 每個關係的模式
- 每個數據的取值類型
- 完整性約束
- 每個關係維護的索引集合
- 每個關係的安全性和權限信息
- 每個關係在磁盤上的物理存儲結構
基本類型
SQL標準支持多種固有類型:
- char(n):固定長度的字符串,用戶指定長度。也可以使用全程character。
- varcharn(n):可變長度的字符串,用戶指定最大長度。等價於character varying。
- smallint:小整數類型(和機器相關的整數類型的子集)。
- numeric(p,d):定點數,精度由用戶指定。這個數有p爲數字,其中d位數字在小數點右邊。
- real,double precision:浮點數與雙精度浮點數,精度與機器有關。
- float(n):精度至少爲n爲浮點數。
每個類型都可能包含一個被稱作空值的特殊值。
char數據類型存放固定長度的字符串。當比較一個char類型和一個varchar類型的時候,也許會期望在比較值之前自動在varchar類型後面加上額外的空格以使長度一致。
SQL也提供nvarchar類型來存放使用Unicode表示的多語言數據。
基本模式定義
create table 命令通用形式的
create table r
(,
,
<完整性約束>
)
create table 命令後面你用分號結束。
- primary key():primary-key聲明表示屬性構成關係的主碼,主碼屬性必須非空且唯一。
- foreign key() references:表示關係中任意元素在數據上的取值必須與關係中某個元組上主碼屬性上的取值。
- not null:一個屬性上的not null約束表明在該屬性中不允許空值。
使用insert命令將數據加載到關係中
使用delete命令從關係中刪除元組
如果想要從一個SQL關係庫中去掉一個關係,我們可以使用drop table命令。
要比
更強的語句。後者保留關係r,刪除r中的所有元素,前者刪除r的所有元組,還刪除r的模式。
使用alter table命令爲已有的關係增加屬性。關係中所有元組在新的屬性上的取值爲null
SQL查詢的基本結構
SQL查詢的基本結構由三個字句構成:select、from和where。查詢輸入是在from字句中列出的關係。這些關係上進行where和select子句中指定的運算,然後產生一個關係作爲結果。
單關係查詢
找出所有教師的名字
如果我們想要強行刪除重複的元素,在select後加入關鍵詞distinct。
如果不想去除重複的元素,可使用all關鍵詞。
select子句還可帶含有+、-、*、/
運算符的表達式。
where子句允許我們只選出那些在from子句的子句結果關係中滿足特定謂詞的元組。
找出所有在Computer Science系並且工資超過70000美元的教師的名字。
where子句中允許使用邏輯連詞and、or和not
,比較運算符爲<、<=、>=、=和<>
多關係查詢
找出所有教師的姓名、以及他們所在系的名稱和系所在建築的名稱。
注意dept_name屬性即出現在instructor關係中,也出現在department中,關係名被用作前綴來說明我們使用的是那個屬性,相反屬性name和building只出現在一個關係中,因而不需要把關係名作爲前綴。
一個SQL查詢可以包括三種類型的子句:select子句、from子句和where子句。每種子句的作用如下:
- select子句用於列出查詢結果中所需要的屬性
- from子句是一個查詢求值中需要訪問的關係列表
- where子句是一個作用在from子句中關係的屬性上的謂詞
一個典型的SQL查詢具有如下形式
儘管各子句必須以select、from、where 的次序寫出,但是理解查詢所有運算的最容易的方式是以運算的順序來考察各子句。首先是from,然後是where,最後是select。
通過from子句定義了一個在該子句中所列出關係上的笛卡爾積。可以用集合理論來形式化定義
此結果關係具有來自from子句中所有關係的所有屬性。
where子句中的謂詞用來限制笛卡爾積所建立的組合,只留下那些對所需答案有意義的組合。
這個語句表明需要teaches.ID和instructor.ID相等的集合。
通常來說,一個SQL查詢的含義可以理解如下:
- 爲from子句中列出的關係產生笛卡爾積
- 在步驟1的結果上應用where子句中指定的謂詞
- 對於步驟2結果中每個元組,輸出select子句中指定的屬性
上述步驟的順序有助於明白一個SQL查詢的結果應該是怎樣的,而不是這個結果是怎樣執行的。在SQL的實際實現中不會執行這種形式的查詢,會通過(儘可能)只產生滿足where子句謂語的笛卡爾積元素來優化執行。
當書寫查詢時,需要小心設置合適的where子句條件。
自然連接
SQL還支持幾種另外的方式使得來自兩個或多個關係的信息可以被連接(join)起來。
**自然連接(natural join)**運算作用於兩個關係,併產生一個關係作爲結果。不同於兩個關係上的笛卡爾積,它將第一個關係的每個元組與第二個關係的所有元組都進行連接。自然連接只考慮哪些在兩個關係模式中都出現的屬性上取值相同的元組對。
可以簡潔寫作:
在一個SQL查詢的from子句中,可以用自然連接將多個關係結合在一起
爲了發揚自然連接的優點,同時避免不必要的相等屬性帶來的危險,SQL提供一種自然連接的構造形式,允許用戶來指定需要哪些相等。
join … using運算中需要給定一個屬性名列表,其兩個輸入中都必須指定名稱的屬性。考慮運算,它與和的自然連接類似,只不過並且成立的前提下。
附加的基本運算
更名運算
SQL提供了一個重要結果關係中屬性的方法。形如as子句old_name as new_name
。
as子句在重要關係時特別有用。重命名關係的一個原因是把一個長的關係名替換成短的。另外一個原因就是爲了適當於需要比較同一個關係中的元組的情況。
像S和T那樣被用來重命名關係的標識符在SQL標準中被稱作相關名稱(correlation name),但是通常也被稱作表別名(table alias)或者相關變量(correlation variable)或者元組變量(tuple variable)。
字符串運算
SQL使用一對單引號來表示字符串,如果單引號是字符串組成的部分,那就用雙引號來表示。
在SQL標準中,字符串上的相等運算是大小寫敏感的。SQL還允許在字符串上有多種函數,不同的數據庫所提供的字符串函數集是不同的。
在字符串上可以使用like操作符來實現模式匹配
- 百分號:匹配任意子串
- 下劃線:匹配任意一個字符
模式是大小寫敏感的。
select子句中的屬性說明
星號*
可以用在select子句中表示所有的屬性。
表示instructor中的所有屬性都被選中。
排列元組的顯示次序
SQL爲用戶體用了一些對關係中元組顯示次序的控制。order by 子句就可以讓查詢結果中元組按排列順序顯示。
按照字母順序列出Physics系的所有教師
order by子句默認使用升序,desc表示降序,或者asc表示升序。
where子句謂詞
爲了簡化where子句,提供了between比較運算符來說明一個值是小於或者等於某個值,同時大於或等於另一個值。
找出工資在90000美元和100000美元之間的教師的姓名
取代
集合運算
SQL作用在關係上的union、interset和except運算對應於數學集合論中的運算。
並運算
找出在2009年秋季開課或者2010年春季開課的或兩個學習都開課的所有課程。
union運算是自動去除重複的。如果想要保留重複,則可以使用union all
交運算
找出在2009年秋季和2010年春季同時開課的所有的課程的集合
同時如果想要保留所以重複,就必須使用interset all
差運算
找出在2009年秋季學期開學但不在2010年春季學期開課的所有課程
如果想要保留所有重複,則必須用except all代替。
空值
SQL涉及空值的任何比較運算的結果視爲unknown(既不是is null,也不是is not null)。
由於在where子句的謂詞可以對比較結果使用諸如and、or和not的布爾運算,這些布爾運算的定義也被擴展到可以處理unknown值。
- and:true and unknown = unknown ,false and unknown = unknown,unknown and unknown = unknown
- or:true or unknown = true ,false or unknwon = unknown ,unknown or unknown = unknown
- not:not unknown = unknown
聚集函數
聚集函數是以值的一個集合爲輸入、返回單個值的函數。SQL提供了五個固有聚集函數:
- 平均值:avg
- 最小值:min
- 最大值:max
- 總和:sum
- 計數:count
基本聚集
找出Computer Science系教師的平均工資
該查詢的結果是一個具有單屬性的關係。可以使用as子句賦個有意義的名稱
有些情況下在計算聚集函數前需先刪除重複元組。可以使用關鍵詞distinct。
分組聚集
有的時候我們不僅希望將聚集函數作用在單個元組集上,而且也希望將其作用在一組元組集上。
找出每個系的平均工資
當SQL查詢使用分組的時候,一個很重要的事情就是需要保證出現在select語句中但沒有被聚集的屬性只能是出現在group by子句中那些屬性。
ID沒有出現在group by子句中,但是出現在select子句中,並且沒有被聚集。因爲在一個特定分組中的每一個教師都有不同的ID,但是每個分組結果輸出一個元組,但是無法確定使用哪一個ID。
having子句
對分組的限定條件要比元組限定條件更有用。SQL的having句,having子句中謂詞在形成分組後起作用,因此可以使用聚集函數。
與select子句的情況相同,任何出現在having子句中,但是沒有被聚集的屬性必須出現在group by子句中,否則查詢就是錯誤的。
包含聚集、group by或having 子句的查詢的含義可通過下述操作序列來定義:
- 與不帶聚集的查詢情況類似,最先根據from子句來計算出一個關係。
- 如果出現了where子句,where子句中的謂詞將應用到from子句的結果關係上。
- 如果出現了group by子句,滿足where謂詞的元組通過 group by子句形成分組,如果沒有group by子句,滿足where謂詞的整個元組集被當做一個分組。
- 如果出現having子句,它將應用到每一個分佈,如果不滿足having子句謂詞的分組將別拋棄
- select子句利用剩下的分組產生查詢結果中的元組,即在每個分組上應用聚集函數來得到單個結果元組。
對於在2009年講授的每個課程段,如果該課程段有至少兩個學生選課,找出選修該課程的所有學生的總分數的平均值
對空值和布爾值的聚集
聚集函數根據以下原則處理空值:除了**count()**外所有的聚集函數都忽略輸入集合中的空值。規定空集的count運算值爲0,其他所有聚集函數在輸入爲空集的情況下返回一個空值。
嵌套子查詢
SQL提供嵌套子查詢機制,子查詢嵌套是另一個查詢中的select-from-where表達式。子查詢嵌套在where子句中,通常用於對集合的成員資格、集合的比較以及集合的基數進行檢查。
集合成員資格
SQL允許測試元組在關係中的成員資格。連接詞in測試元組是否是集合中的成員,集合是由select子句產生的一組構成的。連接詞not in則測試元組是否不是集合中的成員。
2009年秋季開課的課程集合與2010年春季開課的課程集合
現在我們採用另一種方式來查詢這個集合,先查找出2009年的課程,然後在其中查詢出2010年的課程。
這種寫法有助於用戶比較接近自然的方法來思考和查詢。
集合的比較
找出滿足下面條件的所有教師的名字,他們的工資至少比Biology系某一個教師的工資要高
但是SQL提供了另外一種方式書寫上面的查詢。短語“至少比某一個要大”在SQL中用**>some**表示
同樣的SQL也允許<some、<=some、>=some、=some(in)、<>some(not in)。
對於短語“比所有的都大”用**> all** 來表示
類似,也存在<all、<= all、>=all、=all、<>all(not in)但=all不等價於in。
空關係測試
SQL還有一個特性可測試一個子查詢的結果中是否存在元組。exists結構在作爲參數的子查詢非空時返回true值,使用exists結構,我們還能用另外一種方法書寫查詢
在2009年秋季學習和2010年春季學期同時開課的所有課程
上述查詢還說明SQL一個特性,來自外層查詢的一個相關名稱可以用在where子句的子查詢中。使用來自外層查詢相關名稱的子查詢被稱作相關子查詢(correlated subquery)。
我們可以用not exists結構測試子查詢的結果。
重複元組存在性測試
SQL提供了一個布爾函數,用於測試一個子查詢的結果中是否存重複元組,如果作爲參數的子查詢數組中沒有重複的元組。unique結構將返回true值。
找出所有在2009年最多開設一次的課程
unique謂詞在空集上計算出真值。
在不使用unique結構的情況下,等價的方式是
from子句中的子查詢
SQL允許在from子句中使用子查詢表達式,任何select-from-where表達式返回的結果都是關係,因而可以被插入到另一個select-from-where中任何關係可以出現的位置。
找出系統平均工資超過42000美元的那些系中的老師的平均工資
使用from子句中使用子查詢的方式:
with子句
with子句提供定義臨時關係的方法,這個定義只對包含with子句的查詢有效。
找出最大預算值的系
with子句定義了臨時關係max_budget,此關係在隨後的查詢中馬上被使用了。with子句在SQL 1999中引入,現在很多的數據庫都提供了支持。
我們也能用from子句或where子句中的嵌套子查詢書寫上述查詢。with子句使查詢在邏輯上更加清晰,允許在一個查詢內的多個地方使用視圖定義。
查出所有工資總額大於所有系平均總額的系
標量子查詢
SQL允許子查詢出現在返回單個值的表達式能夠出現的任何地方。只要該子查詢只返回包含單個屬性的單個元組,這樣的子查詢稱爲標量子查詢(scalar subquery)。
所有的系以及他們擁有的老師
數據庫的修改
刪除
刪除請求的表達與查詢非常的類似,我們只能刪除整個元組,而不能只刪除某些屬性上的值。
其中表示一個謂詞,代表一個關係。delete語句首先從r中找出所有的使爲真的元組,然後把它們從中刪除。如果省略where語句,則r中所有的元組被刪除,但是關係依然存在。
下面是SQL刪除請求的一些例子
從instructor關係中刪除與Finance系教師相關的所有元組
刪除所有工資在13000美元到15000美元之間的教師
從instructor關係中刪除所有這樣的教師元組,他們在Waston大樓的系工作
插入
待插入元組的數據值必須在相應屬性的域中,同樣,待插入元組的分量數也必須是正確的。
insert語句是的單個元組的插入請求。
插入Computer Science系的信息
SQL允許在insert語句中指定屬性。
更新
update語句與使用insert、delete類似,代更新的元組可以用查詢語句找到。
所有教師的工資將增長5%
上面的更新語句將在instructor關係中每個元組執行一次。
工資低於70000美元的教師漲工資
對於工資低於平均數的教師漲5%的工資
SQL提供case結構,我們可以使用它在一條update語句中執行前面的兩種更新、避免更新次序引發的問題:
case語句的一般格式如下:
標量子查詢在SQL更新語句中也非常的有用,我們可以用set子句中,我們把每個student元組的tot_cred屬性值設爲該該生成功學完的課程的總和。我們可以假設如果一個學生在某門課程的成績既不是F,也不是空,那麼他成功學完了這門課程。
注意子查詢使用來update語句的相關變量S,如果一個學生沒有成功學完任何課程,上述更新的語句將其tot_cred屬性值爲空,如果想要將這個屬性的值設置爲0,可以用另一條update語句來替換成0。將子查詢中**select sum(credits)**子句替換成下面的語句