Table of Contents
3.8.3 空關係測試:exists, not exists
第三章 SQL
3.1 SQL查詢語言概覽
SQL:結構化查詢語言。最新的SQL標準是2008。
SQL語言包括以下幾個部分:
- 數據定義語言(DDL):DDL提供定義關係模式、刪除關係、以及修改關係模式的命令。
- 數據操作語言(DML):DML提供從數據庫中查詢信息,以及在數據庫中插入元組、刪除元組、修改元組的能力。
- 完整性(integrity):DDL包括定義完整性約束的命令,保存在數據庫中的數據必須滿足所定義的完整性約束。破壞完整性約束的更新是不允許的。
- 視圖定義(view definition):DDL包括定義視圖的命令。
- 事務控制(transaction control):SQL包括定義事務的開始和結束的命令。
- 嵌入式SQL和動態SQL(embedded SQL and dynamic SQL): 嵌入式和動態SQL定義SQL語句如何嵌入到通用編程語言,如C和C++
- 授權(authorization):DDL包括定義對關係的訪問權限的命令
3.2 SQL數據定義
SQL DDL不僅能夠定義一組關係,還能定義每個關係的信息,包括:
- 每個關係的模式
- 每個屬性的取值類型
- 完整性約束
- 每個關係維護的索引集合
- 每個關係的安全性和權限信息
- 每個關係在磁盤上的物理存儲結構
3.2.1 基本類型
- char(n): 固定長度的數組。當存入的值不足n位時,自動追加空格。
- varchar(n): 可變長度的數組,用戶指定最大長度n
- int
- smallint:小整數類型
- numeric(p,d):定點數,精度由用戶指定。這個數有p位數字,其中有d位在小數點右邊。
- real, double precision: 浮點數與雙精度浮點數,精度與機器有關
- float(n):精度至少爲n位的浮點數
每種類型都可能包括一個被稱爲空的特殊值。
注意:當比較char和varchar時,是否會自動在varchar類型後面追加空格取決於數據庫的實現。
3.2.2 基本模式定義
- 創建表:其中Ai是屬性,D1是屬性Ai的域。
- 常用的完整性約束:
- primary key(Aj1, Aj2, ..., Ajm): 聲明屬性Aj1, Aj2, ..., Ajm爲關係的主碼。主碼必須非空且唯一。
- foreign key (Ak1, Ak2,..., Akn) references table_B: 聲明關係中任意元組對Ak1, Ak2,..., Akn上的取值必須對應於關係table_B中某元組在主碼上的取值。
- not null: 一個屬性上的not null約束表明該屬性上不允許控制。
- 常用的完整性約束:
注意:SQL禁止破壞完整性約束的任何數據庫更新。
create table R ( A1 D1 not null, A2 D2, ..., An Dn, <完整性約束1>, ..., <完整性約束2>);
- 插入元組:
insert into R (A1, A2, ..., An) values (V1, V2, ..., Vn); insert into R values (V1, V2,..., Vn);
- 刪除元組:
delete from R; --從表R中刪除全部元組 drop table R; --從數據庫中刪除關係R
- 修改關係的屬性
alter table R add A D; --給表R添加屬性A,其域爲D alter table R drop A; --刪除表R的屬性A
3.3 SQL查詢的基本結構
SQL查詢的基本結構由三個子句構成:select, from 和where。
3.3.1 單關係查詢
-- 可以包括重複數據
select A1, A2,.., An from R;
-- 去除重複
select distinct A1, A2,.., An from R;
-- 顯示的不去除重複
select all A1, A2, ..., An from R;
-- select子句可以含有+-*/運算符的算術表達式;運算對象可以是常數或元組的屬性。
select A1, A2, ..., A3 * 1.1 from R;
-- where子句可以包括邏輯連詞and, or 和not
-- 邏輯連詞的運算對象可以使包含比較運算符的<, <=, >, >=, = 和<>的表達式
select A1, A2, ... An from R where A1=V1 and A2=V2;
3.3.2 多關係查詢
SQL查詢的基本結構由三個子句構成:select, from 和where子句構成:
- select子句:列出查詢結果中所需要的屬性
- from子句:一個查詢求值中需要訪問的關係列表
- where子句:一個作用在from子句中關係的屬性上的謂詞
執行順序:from->where->select。
在SQL的實際實現中,它會通過儘可能只產生滿足where子句謂詞的笛卡爾積元素來進行優化執行。如果省略where子句,則會輸出笛卡爾積。
3.3.3 自然連接
笛卡爾積:它將第一個關係的每個元組與第二個關係的所有元組都進行連接。
自然連接:只考慮連接在兩個關係上都出現的屬性上取值相同的元組對。
-- 在R1和R2上都有的屬性做連接
select A1, A2,...,An from R1 natrual join R2;
-- 在僅在A1和A2屬性連接R1和R2 - 自然連接的一種形式
-- 相當於 select A1, A2,...,An from R1, R2 where R1.A1=R2.A1 and R1.A2 = R2.A2;
select A1, A2,...,An from R1 join R2 using (A1, A2);
例如:
select name, course_id from instructor, teaches where instructor.ID = teaches.ID;
--可以簡寫爲:
select name, course_id from instructor natural join teaches;
3.4 附加的基本運算
3.4.1 更名運算 as
oldname as newname
-- 找出滿足下麪條件的所有教師的姓名,他們的工資至少比Biology系的某一個教師的工資要高
select distinct T.name from instructor as T, instructor as B where T.salary>S.salary and S.dept_name = 'Biology';
/*其中T和S 被稱作相關名稱(correlation name)/表別名(table alias)/相關變量(correlation variable)/元組變量(tuple variable)*/
3.4.2 字符串運算
字符串上可以使用的常見函數:
- upper(s):將字符串s轉爲大寫
- lower(s):將字符串s轉爲小寫
- trim(s): 去掉字符串後面的空格
在字符串上使用like操作符實現模式匹配:
- 百分號(%): 匹配任意字符
- 下劃線(_): 匹配任意一個字符
模式是大小寫敏感的。
'Intro%' - 匹配“Intro”打頭的字符串
'%Comp%' - 匹配任何包括“Comp”子串的字符串
'___' - 匹配只含三個字符的字符串
'___%' - 匹配至少包含三個字符的字符串
// 可以使用escape關鍵字來定義轉義符 like 'ab\%cd%' escape
'\' - 匹配以“ab%cd”開頭的字符串
3.4.3 select 子句中的屬性說明
select R.* from R;
3.4.4 排列元組的顯示次序 order by
order by 默認使用升序排列,asc表示升序,desc表示降序
select * from R order by A1; select * from instructor order by salary desc, name asc;
3.4.5 where子句謂詞
- between, not between關鍵字
select name from instructor where salary between 90000 and 100000;
- 在元組上使用比較運算符, 那麼會按照字典順序進行比較
select name, course_id from instructor, teaches where instructor.ID= teaches.ID and dept_name = "Biology";
--可以重寫爲:
select name, course_id from instructor, teaches where (instructor.ID, dept_name) = (teaches.ID, 'Biology');
3.5 集合運算
- 並運算union、union all: 與select子句不同,union運算會自動去除重複;若想保留重複,需要使用union all
(select course_id from section where semester = "Fall" and year = 2019) union (select course_id from section where semester = "Spring" and year = 2020)
- 交運算intersect、intersect all: intersect運算也會自動去除重複
(select course_id from section where semester = "Fall" and year = 2019) intersect (select course_id from section where semester = "Spring" and year = 2020)
- 差運算except、except all: except運算也會自動去除重複
(select course_id from section where semester = "Fall" and year = 2019) except (select course_id from section where semester = "Spring" and year = 2020)
3.6 空值null
空值運算規則:
- 如果算數表達式(+-*/)的任意輸入爲空,則該算數表達式結果爲空
- 涉及空值的任何比較運算的結果視爲unknown(既不是謂詞is null, 也不是is not null),是true和false之外的第三個邏輯值
擴展到unknown的布爾運算:
- and:
- true and unknown ===> unknown
- false and unknown ===> false
- unknown and unknown ===> unknown
- or:
- true or unknown ===> true
- false or unknown ===> unknown
- unknown or unknown ===> unknown
- not
- not unknown ==> unknown
注意:
select distinct會去除重複元組。在該過程中,需要比較兩個元組的對應的屬性值。如果兩個值都是非空並且值相等,或者都爲空,那麼它們是相同的。
但是這與謂詞對待空值的方式不同,謂詞中null = null 會返回unknown,而不是true。
3.7 聚集函數
聚集函數是以值的一個集合爲輸入,返回單個值的函數。
- 常用的聚集函數:
- 平均值 avg
- 最小值 min
- 最大值 max
- 總和 sum
- 計數 count
- 分組聚集 group by
- having子句:對分組限定條件。
包含having和group by 子句的查詢的執行順序:
- 先根據from子句計算出一個關係
- 如果出現where子句,where子句中的謂詞將應用到from子句的結果關係上
- 如果出現group by,則對上面的結果形成分組
- 如果出現having,則執行哈慈那個語句
- 執行select子句
對空值null進行聚集的原則:除了count(*)外,所有的聚集函數都會忽略輸入集合中的空值
3.8 嵌套子查詢
SQL提供嵌套子查詢機制。子查詢是嵌套在另一個查詢中的select-from-where表達式。
3.8.1 集合成員資格:in, not in
in: 測試元組是否是集合中的成員
not in: 測試元組是否不是集合中的成員
select distinct course_id from section where semester = "Fall" and year = 2009 and course_id in
(select course_id from section where semester = "Spring" and year = 2010)
3.8.2 集合的比較
- some:
- < some, <=some, >=some, = some, <>some
注意:= some 等價於 in, <>some不等價於not in
select name from instructor where salary > some (select salary from instructor where dept_name = 'Biology');
- all:
- < all, <=all, >=all, = all , <>all
注意:<>all 等價於not in, =al不等價於in
select name from instructor where salary > all (select salary from instructor where dept_name = 'Biology');
3.8.3 空關係測試:exists, not exists
exists: 測試一個子查詢的結果中是否存在元素
not exists: 測試一個子查詢的結果中是否不存在元素
3.8.4 重複元組存在性測試unique
unique:用於測試一個子查詢的結果中是否含有重複元組。
not unique: 用於測試在一個子查詢結果中是否存在重複元組
-- 找出所有在2009年最多開過一次的課程
select T.course_id from course as T where unique (select R.course_id from section as R where T.course_id = R.course_id and R.year = 2009)
-- 找出所有在2009年最少開過兩次的課程
select T.course_id from course as T where not unique (select R.course_id from section as R where T.course_id = R.course_id and R.year = 2009)
3.8.5 from子句中的子查詢
注意:有的數據庫可以支持對嵌套子查詢的進行屬性重命名。但是oracle不支持。
select dept_name, avg_salary from (select dept_name, avg(salary) from instructor group by dept_name) as dept_avg(dept_name,avg_salary) where avg_salary > 42000;
from子句中的嵌套子查詢不能使用凱子from子句中其他關係的相關變量,但是SQL 2003允許from子句中的子查詢使用關鍵詞lateral最爲前綴,以便訪問from子句中在它前面的表或子查詢中的屬性。
-- 打印每位教師的姓名,工資以及他們所在的系的平均工資
select name, salary, avg_salary from instructor I1, lateral (select avg(salary) as avg_salary from instructor I2 where I2.dept_name = I1.dept_name);
3.8.6 with子句
with子句提供定義臨時關係的方法,這個定義只對包含with子句的查詢有效。
-- 找出具有最大預算值的系
with max_budget(value) as (select max (budget) from department) select budget from department, max_budget where department.budget = max_budget.value;
3.8.7 標量子查詢scalar subquery
若子查詢返回單個屬性的單個元組,則該子查詢稱爲標量子查詢。標量子查詢可以出現select-from-where子句以及having子句中。
-- 列出所有的系,即它們所擁有的教師數
select dept_name, (select count(*) from instructor where department.dept_name = instructor.dept_name) as num_instructors from department;
3.9 數據庫的修改
- 刪除
delete from r where P;
- 插入
insert into r values (v1, v2, ..., vn);
-- 在執行insert前,先執行完select語句
insert into r (select (A1, A2, ..., An) from r where P);
- 更新
update r set A1 = v1 where P;
-- case結構
case when pred1 then res1 when pred2 then res2 ... when predn then resn else res0 end
/* 更新每個student的tot_cred屬性值設爲該生成功 學完的課程的總學分。grade既不是F也不是null,則表明成功學完了該門課程*/
update student S set tot_cred = ( select sum(credits) from takes natural join course where S.ID = takes.ID and takes.grade<>'F' and takes.grode is not null );
/*如果學生沒有成功完成任何一門課程,則tot_cred被設置爲null。 如果希望將這樣的屬性值設爲0,那麼需要使用另一條update */
-- ===>上述sql可改寫爲
update student S set tot_cred = ( select case when sum(credits) is not null then sum(credits) else 0 end from takes natural join course
where S.ID = takes.ID and takes.grade<>'F' and takes.grode is not null);
總結:
- SQL語言包括幾部分:
- 數據定義語言DDL:提供了定義關係模式、刪除關係以及修改關係模式的命令
- 數據操作語言DML:包括查詢語言、以及向數據庫中插入、刪除、修改元組的命令
- SQL的數據定義語言用於創建具有特定模式的關係。除了聲明關係屬性的名稱和類型之外,SQL還允許聲明完整性約束,例如主碼約束和外碼約束
- SQL提供了多種用於數據查詢的語言結構:select-from-where子句。SQL支持自然連接操作。
- SQL提供了對屬性和關係的重命名,以及對查詢結果按照特定屬性排序的機制
- SQL支持關係上的基本集合運算,包括:並、交、和差運算
- SQL通過true,false和unknown來處理包含空值的關係的查詢
- SQL支持聚集函數、可以把關係進行分組,每個分組上單獨運用聚集函數。SQL還支持分組上的集合運算。
- SQL支持在外層查詢的where和from子句中嵌套子查詢。它還在一個表達式返回的單個值所允許出現的地方支持標量子查詢。
- SQL提供了更新、插入、刪除信息的結構。