數據查詢是數據庫最經常使用的功能。在關係數據庫中,查詢操做是由SELECT語句來完成。其語法格式以下:算法
SELECT column_expression FROM table_name | view_name[,table_name | view_name, [,…]] [IN foreign_TABLE] [WHERE... ] [GROUP BY... ] [HAVING... ] [ORDER BY…] [With Owneraccess Option]
其中,column_expression爲目標字段表達式,其語法格式爲:數據庫
[ALL|DISTINCT|TOP] * | table_name.* | [table_name.]column1_name[[AS] alias_name1]express
[, [table_name.] column2_name [ [AS] alias_name2] [, ...]]函數
SELECT語句的主要做用是,從FROM子句指定的數據表或者視圖中找出知足WHERE子句設定的條件的元組,並按照SELECT子句指定的目標字段表達式從新組織這些元組,從而造成新的結果集。若是沒有WHERE子句,則默認選出全部的元組。post
如下主要按子句功能來介紹SELECT語句的使用方法,若是不特別說明,則均指基於表5.10所示的數據表student進行查詢。大數據
【例子】 爲了能看到下文介紹的SELECT語句的執行效果,在用CREATE TABLE語句建立數據表student之後,請接着在SSMS中執行下列的INSERT語句,以在數據庫中建立與表5.10所示內容徹底同樣的數據表:spa
INSERT student VALUES('20170201','劉洋','女','1997-02-03','計算機應用技術',98.5,'計算機系');設計
INSERT student VALUES('20170202','王曉珂','女','1997-09-20','計算機軟件與理論',88.1,'計算機系');code
INSERT student VALUES('20170203','王偉志','男','1996-12-12','智能科學與技術',89.8,'智能技術系');blog
INSERT student VALUES('20170204','嶽志強','男','1998-06-01','智能科學與技術',75.8,'智能技術系');
INSERT student VALUES('20170205','賈簿','男','1994-09-03','計算機軟件與理論',43.0,'計算機系');
INSERT student VALUES('20170206','李思思','女','1996-05-05','計算機應用技術',67.3,'計算機系');
INSERT student VALUES('20170207','蒙恬','男','1995-12-02','大數據技術',78.8,'大數據技術系');
INSERT student VALUES('20170208','張宇','女','1997-03-08','大數據技術',59.3,'大數據技術系');
基本查詢是指基於單表(一個數據表或視圖)的僅僅由SELECT子句和FROM子句構成的SELECT語句。其通常格式以下:
SELECT [ALL|DISTINCT|TOP] * | table_name.* | [table_name.]column1_name[ [AS] alias_name1] [, [table_name.] column2_name [ [AS] alias_name2] [, ...]]
FROM table_name;
因爲視圖的查詢與數據表的查詢是同樣的,如下僅考慮數據表的查詢問題。對於視圖的查詢能夠由此推廣。
有時候但願查詢結果包含全部的字段,這時只需將目標字段表達式設定爲星號「*」便可,也能夠列出全部的字段。
【例子】 下列的SELECT語句實現的就是最簡單的基本查詢,其結果將包含全部字段的所有數據元組:
SELECT * FROM student;
該語句等價於下列的SELECT語句:
SELECT s_no,s_name,s_sex,s_birthday,s_speciality,s_avgrade,s_dept
FROM student;
在不少狀況下,用戶僅對錶中的某些字段感興趣,而且但願這些字段可以按照指定的順序列出。
【例子】 查詢全體學生的平均成績和姓名(平均成績在前,姓名在後)。
SELECT s_avgrade,s_name
FROM student;
執行後結果以下:
s_avgrade s_name
------------------------
98.5 劉洋
88.1 王曉珂
89.8 王偉志
75.8 嶽志強
43.0 賈簿
67.3 李思思
78.8 蒙恬
59.3 張宇
每一字段都是用字段名來「標識」(字段名通常爲英文),例如,第一字段標識爲「s_avgrade」,第二字段標識爲「s_name」。
這對中國用戶來講並不方便,可使用帶關鍵子AS的目標字段表達式來解決,其中AS後面跟由用戶指定的字段標題(關鍵字AS能夠省略)。
【例子】 對於上述問題,可用下列的語句來完成:
SELECT s_avgrade AS 平均成績, s_name AS 姓名 -- AS也能夠省略
FROM student;
執行後結果以下:
平均 成績姓名
------------------------
98.5 劉洋
88.1 王曉珂
89.8 王偉志
75.8 嶽志強
43.0 賈簿
67.3 李思思
78.8 蒙恬
59.3 張宇
查詢結果中的計算字段(列)是指根據數據表中的某一個或者若干個字段進行計算而獲得的新字段,並把它放在查詢結果集中,實際上在數據表中並不存在此字段。
【例子】 要求查詢全體學生的姓名和年齡。因爲數據表student中沒有年齡這一字段,而僅有與之相關的出生日期(birthday)這一字段。必須通過出生日期來計算每一個學生的年齡,相應的SQL語句以下:
SELECT s_name 姓名, Year(getdate())-Year(s_birthday) 年齡
FROM student;
用到兩個系統函數:getdate()和Year(),它們分別用於獲取datetime類型的系統時間和時間的年份。
上述語句執行的結果以下:
姓名 年齡
-----------------------
劉洋 20
王曉珂 20
王偉志 21
嶽志強 19
賈簿 23
李思思 21
蒙恬 22
張宇 20
使用SELECT查詢時,SELECT後面可加上下字段關鍵字,以知足不一樣的查詢要求:
ALL:ALL是默認關鍵字,即當不加任何關鍵字時,表示默認使用ALL做爲關鍵字。它表示要返回全部知足條件的元組。前面介紹的查詢正是這種查詢。
TOP:有兩種格式:TOP n和TOP n PERCENT。第一種格式表示返回前面n個元組,而第二種格式則表示返回前面n%個元組;若是n%不是整數,則向上取整。
DISTINCT:若是帶此關鍵字,則在查詢結果中若包含重複記錄(行),則只返回這些重複元組中的一條。即關鍵字DISTINCT保證了查詢結果集中不會包含重複元組,但與DISTINCTROW不同的是它不會刪除全部的重複元組。
【例5.6】 查詢表student中涉及的不一樣的系別信息。
該查詢要求可用下列的語句完成:
SELECT DISTINCT s_dept 所在的系
FROM student;
執行後結果以下:
所在的系
-----------------
大數據技術系
計算機系
智能技術系
若是在以上語句中不加上關鍵字DISTINCT,則返回下列結果:
所在的系
-----------------
計算機系
計算機系
智能技術系
智能技術系
計算機系
計算機系
大數據技術系
大數據技術系
從以上不難看出關鍵字DISTINCT的做用。若是DISTINCT後面跟有多個字段名,則DISTINCT必須放在第一字段名的前面(即緊跟SELECT以後),而不能放在其餘字段名的前面。
【例子】 下列的語句是正確的。
SELECT DISTINCT s_dept, s_sex
FROM student;
而下面的語句則是錯誤的:
SELECT s_dept, DISTINCT s_sex
FROM student;
【例5.7】 查詢表student中前3條記錄,列出它們全部的字段信息。
該查詢可用帶關鍵字TOP來實現:
SELECT TOP 3 *
FROM student;
若是用下列語句,雖然8*38% = 3.04,但因爲採起向上取整,其結果返回4條記錄:
SELECT TOP 38 PERCENT *
FROM student;
在實際應用中,更多時候是根據必定條件來進行查詢的,即查詢知足必定條件的部分記錄(而不是表中的全部記錄)。WHERE子句將發揮做用,其通常語法格式以下:
SELECT column_expression FROM table_name WHERE condition_expression
condition_expression是條件表達式,一般稱爲查詢條件。查詢條件就是一種邏輯表達式,只有那些使該表達式的邏輯值爲真的記錄才按照目標字段表達式column_expression指定的方式組成一個新記錄而添加到結果集中。
查詢條件是一種邏輯表達式,就能夠用一些邏輯聯結聯結詞來構建這種表達式。經常使用聯結詞包括NOT、OR、AND等,分別表示邏輯意義上的「非」、「或」和「與」。
【例5.8】 要求查詢表student中平均成績爲良好(80~90,但不等於90)的學生的學號、姓名、性別和平均成績。
對於這一查詢要求,可用下列的SELECT語句:
SELECT s_no 學號,s_name 姓名,s_sex 性別, s_avgrade 平均成績
FROM student
WHERE s_avgrade>=80 AND s_avgrade<90;
該語句執行後結果以下:
學號 姓名 性別 平均成績
-------------------------------------------------------------
20170202 王曉珂 女 88.1
20170203 王偉志 男 89.8
WHERE子句雖然語法格式比較簡單,但在查詢中倒是使用得最多。下面介紹的查詢大多都會涉及到WHERE子句,讀者應該深入領會其使用方法。
有時候須要查詢哪些字段值在必定範圍內的記錄,這時可使用帶BETWEEN的查詢語句。其語法格式爲:
SELECT column_expression FROM table_name WHERE column_name [NOT] BETWEEN value1 AND value2;
value1和value2都是字段column_name的具體值,且value1≤value2。該語句的查詢結果是返回全部字段column_name的值落在value1到value2(包括value1和value2)之間範圍內的記錄。
【例5.9】 要求查詢全部出生在1996年08月01日到1997年10月01日之間(包括這兩個日期)的學生,並將他們的姓名、性別、系別、平均成績以及出生年月列出來。
對於這個查詢要求,能夠用下列的語句完成:
SELECT s_name 姓名, s_sex 性別, s_dept 系別, s_avgrade 平均成績,s_birthday 出生年月 FROM student WHERE s_birthday BETWEEN '1996-08-01' AND '1997-10-01’;
執行後結果以下:
姓名 性別 系別 平均成績 出生年月
---------------------------------------------------------------------------------------------------
劉洋 女 計算機系 98.5 1997-02-03
王曉珂 女 計算機系 88.1 1997-09-20
王偉志 男 智能技術系 89.8 1996-12-12
張宇 女 大數據技術系 59.3 1997-03-08
若是要查詢字段column_name的值不落在value1到value2(包括不等於value1和value2)之間的全部記錄,則只需在相應的BETWEEN前加上謂詞NOT便可。
例如,上例中查詢不是出生在1996年08月01日到1997年10月01日之間的學生,可用下列的語句:
SELECT s_name 姓名, s_sex 性別, s_dept 系別, s_avgrade 平均成績,s_birthday 出生年月 FROM student WHERE s_birthday NOT BETWEEN '1996-08-01' AND '1997-10-01’;
執行結果以下:
姓名 性別 系別 平均成績 出生年月
------------------------------------------------------------------------------------------------
嶽志強 男 智能技術系 75.8 1998-06-01
賈簿 男 計算機系 43.0 1994-09-03
李思思 女 計算機系 67.3 1996-05-05
蒙恬 男 大數據技術系 78.8 1995-12-02
BETWEEN只適合於字段值爲數值型的狀況。
IN與BETWEEN具備相似的功能,都是查詢知足字段值在必定範圍內的記錄。但與BETWEEN不一樣的是,IN後面必須跟枚舉的字段值表(字段值的枚舉),即把全部的字段值都列出來,而不能寫爲「value1 AND value2」的形式。這至關於在一個集合中進行查詢,適合於那些不是數值型的狀況。其語法格式爲:
SELECT column_expression FROM table_name WHERE column_name [NOT] IN (value1, value2, …, valuen)
【例5.10】 要求查詢智能技術系和大數據技術系的學生。
對於這個查詢要求,能夠用下列的語句來實現:
SELECT s_no 學號, s_name 姓名, s_sex 性別, s_birthday 出生年月, s_speciality 專業, s_avgrade 平均成績, s_dept 系別 FROM student WHERE s_dept IN ('智能技術系','大數據技術系')
相應的輸出以下:
學號 姓名 性別 出生年月 專業 平均成績 系別
----------------------------------------------------------------------------------------------------------------------------------------------
20170203 王偉志 男 1996-12-12 智能科學與技術 89.8 智能技術系
20170204 嶽志強 男 1998-06-01 智能科學與技術 75.8 智能技術系
20170207 蒙恬 男 1995-12-02 大數據技術 78.8 大數據技術系
20170208 張宇 女 1997-03-08 大數據技術 59.3 大數據技術系
實際上,「column_name IN (value1, value2, …, valuen)」 等價「column_name=value1 OR column_name=value2 OR…OR column_name=valuen」。
上例的查詢語句也等價於:
SELECT s_no 學號, s_name 姓名, s_sex 性別, s_birthday 出生年月, s_speciality 專業, s_avgrade 平均成績, s_dept 系別 FROM student WHERE s_dept='智能技術系' OR s_dept='大數據技術系';
這種IN的語句比帶OR的語句在結構上比較簡潔和直觀。
另外,與BETWEEN相似,對於字段值不在(value1, value2, …, valuen)中的查詢,可經過在IN以前加上NOT來實現。
帶GROUP的查詢就是一般所說的分組查詢,它將查詢結果按照某一字段或某一些字段的字段值進行分組。咱們就能夠對每一組進行相應的操做,而通常的查詢(如上面介紹的查詢)都只能針對每一條記錄進行操做。
用於統計每一組的記錄個數。如下是分組查詢的語法格式:
SELECT column_expression[, count(*)] FROM table_name GROUP BY column_expression [HAVING condition_expression]
HAVING是可選的,它用於對造成的分組進行篩選,留下知足條件condition_expression的組。
【例5.11】 要求查詢表student中各系學生的數量。
(1)對於此查詢,要按系(s_dept)來實現分組,相應的語句以下:
SELECT s_dept 系別, count(*) 人數 FROM student GROUP BY s_dept;
查詢結果以下:
系別 人數
--------------------------------
大數據技術系 2
計算機系 4
智能技術系 2
(2)若是要查詢人數大於或等於2的系的學生數量分佈狀況(每一個繫有多少人),則能夠用HAVING短語來實現。
SELECT s_dept 系別, count(*) 人數 FROM student GROUP BY s_dept HAVING count(*) >= 2;
(3)若是進一步要求在平均成績及格(s_avgrade >= 60)的學生中完成這種分組查詢,即對於平均成績及格的學生,若是要查詢他們人數大於或等於2的系的學生數量分佈狀況,則能夠先用WHERE子句來選擇及格的學生,而後用HAVING短語來實現分組查詢:
SELECT s_dept 系別, count(*) 人數 FROM student WHERE s_avgrade >= 60 GROUP BY s_dept HAVING count(*) >= 2
執行結果以下:
系別 人數
-------------------------
計算機系 3
智能技術系 2
注意:WHERE子句應該在GROUP和HAVING以前出現。
注意:WHERE子句和HAVING短語的做用都同樣,都是用於指定查詢條件。它們是有區別的:
HAVING短語是用於對組設定條件,而不是具體的某一條記錄,從而使得SELECT語句能夠實現對組進行篩選;
WHERE子句是對每一條記錄設定條件的,而不是一個記錄組。
模糊查詢在大多狀況下都是由謂詞LIKE來實現。其通常語法格式爲:
SELECT column_expression FROM table_name WHERE column_name [NOT] LIKE character_string;
column_name的類型必須是字符串類型,character_string表示字符串常數。
該語句的含義是查找字段column_name的字段值與給定字符串character_string相匹配的記錄。
字符串character_string能夠是一個字符串常量,也能夠是包含通配符「_」和「%」的字符串。是否相匹配要根據下列原則來肯定:
「_」(下劃線): 它能夠與任意的單字符相匹配。
「%」(百分號) :它能夠與任意長度字符串(包括空值)相匹配。
除了字符「_」和「%」外,全部其它的字符都只能匹配本身。
【例5.12】 查詢全部姓「王」的學生,並列出他們的學號、姓名、性別、平均成績和系別。
SELECT s_no 學號,s_name 姓名,s_sex 性別,s_avgrade 平均成績,s_dept 系別 FROM student WHERE s_name LIKE '王%';
該語句的查詢結果以下:
學號 姓名 性別 平均成績 系別
---------------------------------------------------------------------------------
20170202 王曉珂 女 88.1 計算機系
20170203 王偉志 男 89.8 智能技術系
這是由於字符串'王%'能夠與任何第一個字爲「王」的名字相互匹配。若是謂詞LIKE後跟'王_',則只能找出任何王姓且姓名僅由兩個字組成的學生;若是謂詞LIKE後跟'%志%',則表示要找出姓名中含有「志」的學生。
注意,因爲字段s_name的數據類型是固定長度的8個字符(char(8)),所以若是s_name值的實際長度不夠8個字符的,則後面以空格填補。
空值null的查詢是指查找指定字段的字段值爲null的記錄。對於這種查詢,首先想到的方法可能就是用帶等號「=」的WHERE子句來實現。但這種查找方法是失敗的。
例如,下列的SELECT語句將找不到任何的記錄,即便存在s_avgrade的字段值爲null的記錄:
SELECT * FROM student WHERE s_avgrade = null -- 錯誤
而正確的寫法應該是:
SELECT * FROM student WHERE s_avgrade IS null -- 正確
【例5.13】 查找全部字段s_avgrade的值爲非空的記錄。
SELECT * FROM student WHERE s_avgrade IS NOT null
有時候咱們但願將查詢結果按照必定的順序進行排列,以方便、快速地從結果集中獲取咱們須要的信息。
例如,按照學生的成績從高到低進行排序,這樣咱們一眼就能夠看出誰的分數最高、誰的最低。而帶ORDER BY子句的SELECT語句就能夠實現對查詢結果進行排序。其通常語法格式以下:
SELECT column_expression FROM table_name ORDER BY column_name [ASC|DESC][,…]
column_name表示排序的依據字段,ASC表示按依據字段進行升序排列,DESC表示按依據字段進行降序排列。若是ASC和DESC都沒有選擇,則按依據字段進行升序排列,即ASC爲默認值。
【例5.14】 對錶student中的男同窗按成績進行降序排序。
SELECT * FROM student WHERE s_sex = '男' ORDER BY s_avgrade DESC
執行後結果以下:
學號 姓名 性別 出生日期 專業 平均成績 系別
---------------------------------------------------------------------------------------------------------------------------------------
20170203 王偉志 男 1996-12-12 智能科學與技術 89.8 智能技術系
20170207 蒙恬 男 1995-12-02 大數據技術 78.8 大數據技術系
20170204 嶽志強 男 1998-06-01 智能科學與技術 75.8 智能技術系
20170205 賈簿 男 1994-09-03 計算機軟件與理論 43.0 計算機系
【例子】 若是但願在成績相同的狀況下,進一步按照學號進行升序排列,則能夠經過在ORDER BY後面增長字段s_no的方法來實現。相應的語句以下:
SELECT * FROM student WHERE s_sex = '男' ORDER BY s_avgrade DESC, s_no ASC
在上面的語句中,排序的原理是這樣的:首先按照平均成績對記錄進行降序排序(由於選擇了DESC);若是查詢結果包含有平均成績相同的記錄,那麼這時按平均成績就沒法對這些具備相同平均成績的記錄進行排序,這時SELECT語句將自動按照下一字段——學號(s_no)對這些記錄進行升序排序(升序是默認排序方式);若是s_no後面還有其餘字段,那麼排序原理也依次類推。
同時涉及到兩個或者兩個以上數據表的查詢稱爲鏈接查詢。鏈接查詢能夠找出多個表之間蘊涵的有用信息,實際上它是關係數據庫中最主要的查詢。鏈接查詢主要包括等值鏈接查詢、天然鏈接查詢、外鏈接查詢以及交叉鏈接查詢等。但交叉鏈接查詢沒有實際意義,且運用的不多,在此不做介紹。
鏈接查詢涉及到兩種表。除了表5.10所示的數據表student之外,咱們還需建立另外一張數據表——選課表SC。該表的結構和內容分別如表5.11和表5.12所示。
先用下列語句建立選課表SC:
CREATE TABLE SC( s_no char(8), c_name varchar(20), c_gradenumeric(3,1) CHECK(c_grade >= 0 AND c_grade <= 100), PRIMARY KEY(s_no, c_name) --將(s_no, c_name)設爲主鍵 );
而後用下列INSERT插入如表5.12所示的數據,以便觀察鏈接查詢的效果:
INSERT SC VALUES('20170201','英語',80.2); INSERT SC VALUES('20170201','數據庫原理',70.0); INSERT SC VALUES('20170201','算法設計與分析',92.4); INSERT SC VALUES('20170202','英語',81.9); INSERT SC VALUES('20170202','算法設計與分析',85.2); INSERT SC VALUES('20170203','多媒體技術',68.1);
不特別說明,在本節中介紹的鏈接查詢主要是基於表student和表SC進行的。
在使用鏈接查詢時,按照必定的條件在兩個或多個表中提取數據並組成新的記錄,全部這些記錄的集合便構成了一個新的關係表。那麼這個條件就稱爲鏈接條件,表示爲join_condition。鏈接條件具備下列的形式:
[table1_name.]columni_name comp_oper [table2_name.]columnj_name
其中,comp_oper表示比較操做符,主要包括=、>(大於)、<(小於)、>=(大於等於)、<=(小於等於)、!=(不等)。鏈接條件有意義的前提是字段column1_name和column2_name是可比較的。
當鏈接條件的比較操做符comp_oper爲等號「=」時,相應的鏈接就稱爲等值鏈接。對於表table1_name和表table2_name之間的等值鏈接,其通常格式能夠表示以下:
SELECT [table1_name.]column1_name[, …], [table2_name.]column1_name[, …] FROM table1_name, table2_name WHERE [table1_name.]columni_name = [table2_name.]columnj_name
注意,對於字段名前面的表名是否須要顯式標出,這取決於兩個表中是否都有與此同名的字段。若是有,則必須冠以表名,不然能夠不寫表名。
鏈接條件中相互比較的兩個字段必須是可比的,不然比較將無心義。但可比性並不意味着兩個字段的數據類型必須同樣,而只要求它們在語義上可比便可。
【例子】 對於整型的字段和浮點型的字段,雖然數據類型不一樣,但它們倒是可比的;而將整型的字段和字符串型的字段進行比較,那是無心義的。
對於鏈接操做,能夠這樣來理解:首先取表table1_name中的第一條記錄,而後從表table2_name中的第一條記錄開始依次掃描全部的記錄,並檢查表table1_name中的第一條記錄與表table2_name中的當前記錄是否知足查詢條件,若是知足則將這兩條記錄並接起來,造成結果集中的一條記錄。當對錶table2_name掃描完了之後,又從表table1_name中的第二條記錄開始,重複上面相同的操做,直到表table1_name中全部的記錄都處理完畢爲止。
【例5.15】 要求查詢選課學生的學號、姓名、性別、專業、系別以及所選的課程名稱和成績。
這個查詢要求就涉及到兩個表的查詢,由於學生的基本信息包含在表student中,而選課信息則包含在表SC中。一個學生是否選課能夠這樣獲知:若是表SC中有他的學號,則代表該學生已經選課,不然沒有選課。上述查詢問題就能夠表述爲,掃描表student和表SC中的每一條記錄,若是這兩個表中的當前記錄在各自的字段s_no上取值相等,則將這兩條記錄按照指定的要求並接成一個新的記錄並添加到結果集中。這種查詢是以表student中的字段s_no和表SC中的字段s_no是否相等爲查詢條件的,因此這種查詢就是等值查詢。該等值查詢的實現語句以下:
SELECT student.s_no 學號, s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, c_name 課程名稱, c_grade 課程成績 FROM student, SC WHERE student.s_no = SC.s_no
執行後的結果以下:
學號 姓名 性別 專業 系別 課程名稱 課程成績
---------------------------------------------------------------------------------------------------------------------------------------
20170201 劉洋 女 計算機應用技術計算機系 數據庫原理 70.0
20170201 劉洋 女 計算機應用技術計算機系 算法設計與分析 92.4
20170201 劉洋 女 計算機應用技術計算機系 英語 80.2
20170202 王曉珂 女 計算機軟件與理論計算機系 算法設計與分析 85.2
20170202 王曉珂 女 計算機軟件與理論計算機系 英語 81.9
20170203 王偉志 男 智能科學與技術智能技術系 多媒體技術 68.1
表student和表SC中都有字段s_no,必須在其前面冠以表名,以明確s_no是屬於哪個表中的字段。若是在涉及的兩個表中還有其餘同名的字段,也需進行一樣的處理。
若是以爲表名過長,使用起來比較麻煩,則能夠利用AS來定義別名,經過使用別名來進行表的鏈接查詢。
【例子】 上述的等值鏈接查詢語句跟下面的查詢語句是等價的:
SELECT a.s_no 學號, s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, c_name 課程名稱, c_grade 課程成績 FROM student as a, SC as b WHERE a.s_no = b.s_no
上述SELECT語句中,利用AS將表名student和SC分別定義爲a和b,而後經過a和b來進行鏈接查詢,從而簡化代碼。
若是在上述的等值鏈接查詢語句中去掉WHERE子句,則獲得下列的SELECT語句:
SELECT student.s_no 學號, s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, c_name 課程名稱, c_grade 課程成績 FROM student, SC
該語句將造成表student和表SC的笛卡兒積。笛卡兒積是將兩個表中的每一條記錄分別並接而獲得的結果集。笛卡兒積中記錄的條數是兩個表中記錄條數的乘積,
天然鏈接其實是一種特殊的等值鏈接,這種鏈接在等值鏈接的基礎上增長如下兩個條件而造成的:
(1)參加比較的兩個字段必須是相同的,即同名同類型;
(2)結果集的字段是參加鏈接的兩個表的字段的並集,但去掉了重複的字段。
【例5.16】 實現表student和表SC的天然鏈接查詢。
可用下列的SELECT語句來實現:
SELECT student.s_no 學號, s_name 姓名, s_sex 性別, s_birthday 出生日期, s_speciality 專業, s_avgrade 平均成績,s_dept 系別, c_name 課程名稱, c_grade 課程成績 FROM student, SC WHERE student.s_no = SC.s_no
上述語句執行獲得的天然鏈接結果如表5.13所示。
該結果集中的字段包含了表student和表SC中全部的字段,並去掉了重複字段SC.s_no而保留student.s_no(固然,也能夠去掉student.s_no而保留SC.s_no),並且無其餘重複字段,因此該等值查詢是天然鏈接查詢。
以上介紹的都是基於兩個不一樣的表進行鏈接查詢。但有時候須要將一個表跟它自身進行鏈接查詢,以完成相應的查詢任務,這種查詢就稱爲自鏈接查詢。
在使用自鏈接查詢時,雖然實際操做的是同一張表,但在邏輯上要使之分爲兩張表。這種邏輯上的分開能夠在SQL Server中經過定義表別名的方法來實現,即爲一張表定義不一樣的別名,這樣就造成了有相同內容、但表名不一樣的兩張表。
【例5.17】 要求查詢表student中與「劉洋」在同一個專業的全部學生的學號、姓名、性別、專業和平均成績(包括「李好」)。
這種查詢的難處在於,咱們不知道「劉洋」的專業是什麼,若是知道了她的專業,那麼該查詢就很容易實現。必須從姓名爲「劉洋」的學生記錄中得到她的專業,而後由專業獲取相關學生的信息。這種查詢難以用單表查詢來實現。若是使用自鏈接查詢,那麼問題就很容易獲得解決。
自鏈接查詢的方法以下:爲表student建立一個別名b,這樣student和b便造成邏輯上的兩張表。而後經過表student和表b的鏈接查詢實現本例的查詢任務。但這種自鏈接查詢要用到JOIN…ON…子句。查詢語句以下:
SELECT b.s_no 學號, b.s_name 姓名, b.s_sex 性別,b.s_speciality 專業, b.s_avgrade 平均成績 FROM student AS a-- 爲student建立別名a JOIN student AS b -- 爲student建立別名b ON (a.s_name='劉洋' AND a.s_speciality = b.s_speciality);
該語句運行結果以下:
學號 姓名 性別 專業 平均成績
--------------------------------------------------------------------------
20170201劉洋 女 計算機應用技術 98.5
20170206李思思 女 計算機應用技術 67.3
定義student的一個別名也能夠實現此功能:
SELECT b.s_no 學號, b.s_name 姓名, b.s_sex 性別,b.s_speciality 專業, b.s_avgrade 平均成績 FROM student JOIN student AS b -- 爲student建立別名b ON (student.s_name='劉洋' AND student.s_speciality = b.s_speciality);
上述介紹的鏈接查詢中,只有那些知足查詢條件的記錄才被列出來,而不知足條件的記錄則「不翼而飛」,這在有的應用中並不合適。
例如,在對錶student和表SC進行等值鏈接查詢後,學號爲「20120204」等學生因爲沒有選課,因此在查詢結果中就沒有關於這些學生的信息。可是不少時候咱們但願可以將全部學生信息所有列出,對於沒有選課的學生,其對應課程字段和課程成績字段留空便可。上述鏈接查詢方法就不適用了,須要引進另外一種鏈接查詢——外鏈接查詢。
外鏈接查詢的語法格式爲:
SELECT [table1_name.]column1_name[, …], [table2_name.]column1_name[, …] FROM table1_name LEFT|RIGHT [OUTER] JOIN table2_name ON join_condition
若是在FROM子句中選擇關鍵字LEFT,則該查詢稱爲左外鏈接查詢;若是選擇關鍵字RIGHT,則該查詢稱爲右外鏈接查詢。
在左外鏈接查詢中,對於表table1_name(左邊的表)中的記錄無論是否知足鏈接條件join_condition,它們都將將被列出;而對錶table2_name(右邊的表)中的記錄,只有知足鏈接條件join_condition的部分才被列出。
在右外鏈接查詢中,對於表table2_name中的記錄無論是否知足鏈接條件join_condition,它們都將將被列出;而對錶table1_name中的記錄,只有知足鏈接條件join_condition的部分才被列出。
【例5.18】 查詢全部學生的基本信息,若是他們選課了則同時列出相應的課程信息(含姓名、性別、專業、系別以及課程名稱和課程成績)。
這種查詢的基本要求是,首先無條件地列出全部學生相關信息;其次對於已經選課的學生,則列出其相應的選課信息,而對於沒有選課的學生,其相應的字段留空。即表student中的記錄要無條件列出,而表SC中的記錄只有知足鏈接條件(已選課)的部分才能列出。這須要用外鏈接查詢來實現,其實現語句以下:
SELECT s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, SC.c_name 課程名稱, SC.c_grade 課程成績 FROM student
LEFT JOIN SC ON (student.s_no = SC.s_no);
以上採用的是左外鏈接查詢。也能夠將表student和表SC的位置調換一下,改用右外鏈接查詢,其實現語句以下:
SELECT s_name 姓名, s_sex 性別, s_speciality 專業, s_dept 系別, SC.c_name 課程名稱, SC.c_grade 課程成績 FROM SC RIGHT JOIN student ON (student.s_no = SC.s_no);
以上兩種外鏈接查詢語句的做用都是同樣的,執行後都獲得以下結果:
姓名 性別 專業 系別 課程名稱 課程成績
----------------------------------------------------------------------------------------------------------------------------
劉洋 女計算機應用技術計算機系 數據庫原理70.0
劉洋 女計算機應用技術計算機系 算法設計與分析92.4
劉洋 女計算機應用技術計算機系 英語80.2
王曉珂 女計算機軟件與理論計算機系 算法設計與分析85.2
王曉珂 女計算機軟件與理論計算機系 英語81.9
王偉志 男智能科學與技術智能技術系 多媒體技術68.1
嶽志強 男智能科學與技術智能技術系 NULLNULL
賈簿 男計算機軟件與理論計算機系 NULLNULL
李思思 女計算機應用技術計算機系 NULLNULL
蒙恬 男大數據技術大數據技術系 NULLNULL
張宇 女大數據技術大數據技術系 NULLNULL
從以上結果能夠看出,「嶽志強」等雖然沒有選課,但他們的基本信息仍是被列出了,其相應顯示選課信息的位置則留空(NULL)。
一個查詢A能夠嵌入到另外一個查詢B的WHERE子句中或者HAVING短語中,由這種嵌入方法而獲得的查詢就稱爲嵌入查詢。查詢A稱爲查詢B的子查詢(或內層查詢),查詢B稱爲查詢A的父查詢(或外層查詢、主查詢等)。
觀察下面的例子:
SELECT s_no,s_name -- FROM student ----父查詢 WHERE s_no IN( -- SELECT s_no -- FROM SC ----子查詢 WHERE c_name = '算法設計與分析') --
該查詢就是一個嵌套查詢,它找出了選「算法設計與分析」這門課的學生的學號和姓名。其中,括號內的查詢爲子查詢,括號外的查詢爲父查詢。子查詢還能夠嵌套其餘的子查詢,即SQL語言容許多層嵌套查詢。
執行嵌套查詢的過程:首先執行最內層的子查詢,而後用子查詢的結果構成父查詢的WHERE子句,並執行該查詢;父查詢產生的結果又返回給其父查詢的WHERE子句,其父查詢又執行相同的操做,直到最外層查詢執行完爲止。也就是說,嵌套查詢的執行過程是由裏向外。
嵌套查詢的優勢是,每一層的查詢都是一條簡單的SELECT語句,其結構清晰,易於理解。但不能對子查詢的結果進行排序,即子查詢不能帶ORDER BY子句。
如下將根據所使用謂詞的不一樣來介紹各類嵌套查詢,而且假設討論的嵌套查詢是由子查詢和父查詢構成。對於多層的嵌套查詢,不難由此推廣。
帶IN的嵌套查詢是指父查詢和子查詢是經過謂詞IN來鏈接的一種嵌套查詢,也是用得最多的嵌套查詢之一。其特色是,子查詢的返回結果被看成是一個集合,父查詢則判斷某一字段值是否在該集合中,以肯定是否要輸出該字段值對應的記錄的有關信息。
【例5.19】 查詢「王偉志」和「蒙恬」所在專業的全部學生信息。
這個查詢的解決過程是,首先找出他們所在的專業,而後根據專業來查找學生。爲此能夠分爲兩步走。
首先肯定「王偉志」和「蒙恬」所在的專業:
SELECT student.s_speciality FROM student WHERE student.s_name = '王偉志' OR student.s_name = '蒙恬‘
上述語句的返回結果是('智能科學與技術', '大數據技術')。下一步要作的就是查找全部專業爲智能科學與技術或大數據技術的學生。相應的SELECT語句以下:
SELECT * FROM student WHERE student.s_speciality IN ('智能科學與技術', '大數據技術');
將中間結果(‘智能科學與技術’, ‘大數據技術’)去掉,代之以產生該結果的SELECT語句,因而獲得了下列的嵌套查詢:
SELECT * FROM student WHERE student.s_speciality IN ( SELECT student.s_speciality FROM student WHERE student.s_name = '王偉志' OR student.s_name = '蒙恬');
執行該嵌套查詢後獲得以下的結果,該結果與咱們預想的徹底一致:
s_nos_names_sexs_birthday s_speciality s_avgrade s_dept
------------------------------------------------------------------------------------------------------------------------------
20170203王偉志 男1996-12-12 智能科學與技術89.8智能技術系
20170204嶽志強 男1998-06-01 智能科學與技術75.8智能技術系
20170207蒙恬 男1995-12-02 大數據技術 78.8大數據技術系
20170208張宇 女1997-03-08 大數據技術 59.3大數據技術系
對於這個例子,若是運用鏈接查詢,會顯得比較複雜。但使用帶IN的嵌套查詢,無論在問題的解決思路上仍是在SELECT語句的構造上都顯得更具條理性和直觀性,並且僅涉及到一個邏輯表(不用建立別名)。
比較運算符是指>、<、=、>=、<=、<>等符號。這些符號能夠將一個字段與一個子查詢鏈接起來構成一個邏輯表達式。以這個邏輯表達式爲查詢條件的查詢就構成了父查詢。
通常來講,這種比較只能是基於單值進行的,因此要求子查詢返回的結果必須爲單字段值。
能夠返回('智能科學與技術'),但返回('智能科學與技術', '大數據技術')則是不容許的。在例5.19中,若是將其嵌套查詢中的謂詞IN改成任意一個比較運算符,都會產生錯誤。緣由是,該嵌套查詢中的子查詢返回的不是單字段值,而是兩個字段值。
【例5.20】 查詢全部平均成績比「蒙恬」低的學生,並列出這些學生的學號、姓名、專業和平均成績。
這個查詢的關鍵是首先要找出「蒙恬」的平均成績,而後才能據此找出其餘有關學生的信息。因爲「蒙恬」的平均成績是惟一的,因此咱們能夠構造以下的子查詢:
SELECT s_avgrade FROM student WHERE s_name = '蒙恬';
該查詢返回的結果是78.8。而後由此構造父查詢:
SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade < 78.8
把中間結果78.8去掉之後,將以上兩個查詢合起來,獲得下列的嵌套查詢:
SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade < ( SELECT s_avgrade FROM student WHERE s_name = '蒙恬')
上述嵌套查詢後結果以下:
學號 姓名專業 平均成績
----------------------------------------------------------------------------------------
20170204嶽志強 智能科學與技術75.8
20170205賈簿 計算機軟件與理論 43.0
20170206李思思 計算機應用技術67.3
20170208張宇 大數據技術 59.3
在SQL Server 2014中,子查詢在比較運算符以後或者以前都可有可無,只要查詢條件返回的真值同樣,則查詢結果都相同。例如,下列的嵌套查詢與上面的嵌套查詢是等價的,查詢結果都同樣:
SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE ( SELECT s_avgrade FROM student WHERE s_name = '蒙恬') > s_avgrade;
在使用謂詞EXISTS的嵌套查詢中,只要子查詢返回非空的結果,則父查詢的WHERE子句將返回邏輯真,不然返回邏輯假。至於返回的結果是什麼類型的數據,對這種嵌套查詢是可有可無,因此在父查詢的目標字段表達式都用符號*,即便給出字段名也無實際意義。
帶EXISTS的嵌套查詢與前面介紹的嵌套查詢的最大區別在於,它們執行的方式不同。帶EXISTS的嵌套查詢是先執行外層,後執行內層,再回到外層。具體講,對於每一條記錄,父查詢先從表中「抽取」出來,而後「放到」子查詢中並執行一次子查詢;若是該子查詢返回非空值(致使WHERE子句返回邏輯真),則父查詢將該記錄添加到結果集中,直到全部的記錄都被進行這樣的處理爲止。顯然,父查詢做用的表中有多少條記錄,則子查詢被執行多少次。在這種查詢中,子查詢依賴於父查詢,因此這類查詢又稱爲相關子查詢。
前面介紹的嵌套查詢中,先執行子查詢,後執行父查詢。子查詢與父查詢無關,因此這類查詢稱爲不相關子查詢。
【例5.21】 查詢全部選修了《算法設計與分析》的學生學號、姓名和專業。
學生選修課程的信息放在表SC中,而學生的學號、姓名和專業信息則放在表student中,因此該查詢要涉及到兩個表。顯然,該查詢能夠用不少種方法來實現,下面咱們考慮運用帶EXISTS的嵌套查詢來完成。相應的SELECT語句以下:
SELECT s_no 學號, s_name 姓名, s_speciality 專業 FROM student WHERE EXISTS( SELECT * FROM SC WHERE student.s_no = s_no AND c_name = '算法設計與分析');
在執行該嵌套查詢時,父查詢先取表student中的第1條記錄,記爲r1;而後執行一次子查詢,這時發現表SC中存在s_no字段值與r1的s_no字段值相等的記錄(記爲r2),並且r2在c_name字段上的取值爲「算法設計與分析」,因此子查詢返回記錄r2(非空);因爲第1條記錄(r1)使得子查詢返回值爲非空,因此父查詢的WHERE子句返回邏輯真,這樣父查詢便將第1條記錄添加到結果集中;重複上述過程,直到表student中全部的記錄都被處理完爲止。
本查詢也能夠用帶謂詞IN的嵌套查詢來實現,其查詢實現思想也比較直觀。首先用子查詢返回表SC中全部選修了《算法設計與分析》的學生學號的集合,而後用父查詢找出表student中學號在該集合中的學生。相應的查詢語句以下:
SELECT s_no 學號, s_name 姓名, s_speciality 專業 FROM student WHERE s_no IN ( SELECT s_no FROM SC WHERE c_name = '算法設計與分析');
SELECT語句返回的結果是若干個記錄的集合。集合有其固有的一些運算,如並、交、差等。從集合運算的角度看,能夠將每個SELECT語句看成是一個集合。因而,能夠對任意兩個SELECT語句進行集合運算。在SQL語言,提供了並(UNION)、交(INTERSECT)和差(EXCEPT)等幾個集合運算。
兩個查詢的並(UNION)是指將兩個查詢的返回結果集合併到一塊兒,同時去掉重複的記錄。並運算的前提是,兩個查詢返回的結果集在結構上要一致,即結果集的字段個數要相等以及字段的類型要分別相同。
【例5.22】 查詢專業爲大數據技術或者平均成績在良好以上(>=80)的學生,並列出他們的學號、姓名、專業和平均成績。
這個查詢能夠看做是如下兩個查詢並:
-- 查詢專業爲大數據技術的學生
SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_speciality = '大數據技術';
-- 查詢平均成績在良好以上的學生
SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade >= 80;
以上這兩個查詢語句執行後所得的結果分別以下:
學號姓名 專業 平均成績
-------------------------------------------------------------------------------
20170207 蒙恬 大數據技術 78.8
20170208 張宇 大數據技術 59.3
學號姓名專業 平均成績
-------------------------------------------------------------------------------
20170201 劉洋 計算機應用技術 98.5
20170202 王曉珂 計算機軟件與理論 88.1
20170203 王偉志 智能科學與技術 89.8
將以上兩個SELECT語句用關鍵字UNION連起來就實現了兩個查詢的並:
(SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_speciality = '大數據技術') UNION (SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade >= 80);
以上語句執行後獲得以下結果:
學號 姓名 專業 平均成績
--------------------------------------------------------------------
20170201 劉洋 計算機應用技術 98.5
20170202 王曉珂 計算機軟件與理論 88.1
20170203 王偉志 智能科學與技術 89.8
20170207 蒙恬 大數據技術 78.8
20170208 張宇 大數據技術 59.3
這個結果正好是上述兩個查詢結果集的並。
【例5.23】 查詢專業爲智能科學與技術並且平均成績在良好以上(>=80)的學生,並列出他們的學號、姓名、專業和平均成績。
該查詢能夠看做是專業爲智能科學與技術的學生集合和平均成績在良好以上的學生集合的交集。
基於交運算的SQL語句以下:
(SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_speciality = '智能科學與技術') INTERSECT (SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade >= 80);
此SQL語句運行結果以下:
學號 姓名 專業 平均成績
------------------------------------------------------------------------------
20170203 王偉志 智能科學與技術 89.8
【例5.24】 查詢專業爲智能科學與技術並且平均成績在良好如下(<80)的學生,並列出他們的學號、姓名、專業和平均成績。
該查詢能夠看做是專業爲智能科學與技術的學生集合與平均成績在良好以上的學生集合的差集。
基於差運算的SQL語句以下:
(SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_speciality = '智能科學與技術') EXCEPT (SELECT s_no 學號, s_name 姓名, s_speciality 專業, s_avgrade 平均成績 FROM student WHERE s_avgrade >= 80);
此SQL語句運行結果以下:
學號姓名 專業 平均成績
-------------------------------------------------------------------------
20170204嶽志強 智能科學與技術75.8