數據庫之數據查詢
數據庫是以select語句為基本對數據庫進行信息查詢的,這裏面有很多使用方式,下面對此做一一總結。數據庫查詢語句的一般格式為:
select [all | distinct]<目標列表達式>[,<目標列表達式>]---
from <表名或視圖名>[,<表名或視圖名>]---
[where <條件表達式>]
[group by <列名1>[having <條件表達式>]]
[order by <列名2>[ASC|DESC]];
其中,如果有group by子句,則將結果按<列名1>的值進行分組,該屬性列值相等的元祖為一個組。通常會在每組中使用聚集函數,如果group by子句中帶有having短語,則只有在滿足指定條件的組才給輸出來。
如果有order by子句,則結果按<列名2>的值升序或降序排序。例如有表Student,其值如下:
mysql> select * from Student;
+--------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+--------+--------+------+------+-------+
| sa1211 | Lily | F | 19 | MA |
| sa1212 | ello | F | 19 | CS |
| sa1213 | Hello | M | 20 | CS |
| sa1214 | Shely | F | 19 | IS |
| sa1215 | Shelly | F | 19 | CS |
| sa1216 | 趙三 | F | 19 | CS |
| sa1217 | 趙四 | F | 19 | CS |
| sa1218 | 張良 | F | 19 | CS |
| sa1219 | 張子房 | F | 19 | CS |
+--------+--------+------+------+-------+
1、查詢經過計算的值,例如查詢全體學生的姓名以及其出生年份,並用小寫字母表示所在院系:
mysql> select Sname,"year of birth:",2017-Sage,lower(Sdept) from Student;
+--------+----------------+-----------+--------------+
| Sname | year of birth: | 2017-Sage | lower(Sdept) |
+--------+----------------+-----------+--------------+
| Lily | year of birth: | 1998 | ma |
| ello | year of birth: | 1998 | cs |
| Hello | year of birth: | 1997 | cs |
| Shely | year of birth: | 1998 | is |
| Shelly | year of birth: | 1998 | cs |
| 趙三 | year of birth: | 1998 | cs |
| 趙四 | year of birth: | 1998 | cs |
| 張良 | year of birth: | 1998 | cs |
| 張子房 | year of birth: | 1998 | cs |
+--------+----------------+-----------+--------------+
2、選擇表中若幹元組
2.1 取消重復的行,例如查詢出所有的院系,去掉重復的值,如下:
mysql> select distinct Sdept from Student;
+-------+
| Sdept |
+-------+
| MA |
| CS |
| IS |
+-------+
2.2 查詢滿足條件的元組,可以通過where子句進行實現,常用的查詢條件如下:
查詢條件 | 謂詞 |
比較 | =,>,<,>=,<=,!=,!>,!<;NOT+上述比較運算符 |
確定範圍 | BETWEEN AND,NOT BETWEEN AND |
確定集合 | IN,NOT IN |
字符匹配 | LIKE,NOT LIKE |
空值 | IS FULL,IS NOT FULL |
多重條件 | AND,OR,NOT |
例如查詢計算機科學系(CS),數學系(MA)學生的姓名和性別。
mysql> select Sname,Ssex from Student where Sdept in (‘CS‘,‘MA‘);
+--------+------+
| Sname | Ssex |
+--------+------+
| Lily | F |
| ello | F |
| Hello | M |
| Shelly | F |
| 趙三 | F |
| 趙四 | F |
| 張良 | F |
| 張子房 | F |
+--------+------+
與IN相對的謂詞是NOT IN表示要查找的屬性不在指定屬性集合的範圍內。
字符串匹配查詢,查找所有不姓“趙”的學生:
mysql> select * from Student where Sname not like "趙%";
+--------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+--------+--------+------+------+-------+
| sa1211 | Lily | F | 19 | MA |
| sa1212 | ello | F | 19 | CS |
| sa1213 | Hello | M | 20 | CS |
| sa1214 | Shely | F | 19 | IS |
| sa1215 | Shelly | F | 19 | CS |
| sa1218 | 張良 | F | 19 | CS |
| sa1219 | 張子房 | F | 19 | CS |
+--------+--------+------+------+-------+
2.3 聚集函數,sql有很多聚集函數,主要有:
count([distinct|all]*) 統計元組個數
count([distinct |all <列名>]) 統計一列中值的個數
SUM([distinct |all <列名>])計算一列值的總和(需是數值類型)
AVG([distinct |all <列名>]) 計算一列值的平均數(需是數值類型)
MAX([distinct |all <列名>])計算一列值的最大數
MIN([distinct |all <列名>])計算一列值的最小數
如果指定distinct短語,表示計算時需要取消指定列中的重復值。如果不指定distinct或指定All短語(all可缺省),則表示不取消重復值。
例如,計算每一個院系的學生個數,如下:
mysql> select count(*),Sdept from Student group by(Sdept);
+----------+-------+
| count(*) | Sdept |
+----------+-------+
| 7 | CS |
| 1 | IS |
| 1 | MA |
+----------+-------+
選出人數大於3的院系,以及該院系的人數:
mysql> select count(*),Sdept from Student group by(Sdept) having count(*)>3;
+----------+-------+
| count(*) | Sdept |
+----------+-------+
| 7 | CS |
+----------+-------+
這裏先用group by進行分組,然後再用count對每一組計數。having短語給出了選擇組的條件,只有滿足條件的組才會被選出。
3、連接查詢
3.1 等值連接和非等值連接查詢
根據上表中的“比較”和“範圍”條件,當連接運算符為=時,表示為等值連接,使用其他運算符為非等值連接。例如,學生表student,選課表sc,這兩個表的連接是通過公共屬性Sno實現的。利用該屬性實現的連接查詢如下:
mysql> select student.*,sc.*
-> from student,sc
-> where student.Sno=sc.Sno;
+--------+-------+------+------+-------+--------+-----+-------+
| Sno | Sname | Ssex | Sage | Sdept | Sno | Cno | Grade |
+--------+-------+------+------+-------+--------+-----+-------+
| sa1211 | Lily | F | 19 | MA | sa1211 | 1 | 89 |
| sa1211 | Lily | F | 19 | MA | sa1211 | 2 | 90 |
| sa1211 | Lily | F | 19 | MA | sa1211 | 3 | 90 |
| sa1212 | ello | F | 19 | CS | sa1212 | 1 | 78 |
| sa1212 | ello | F | 19 | CS | sa1212 | 3 | 90 |
+--------+-------+------+------+-------+--------+-----+-------+
該語句的查詢過程是這樣的,首先在表student中找到第一個元組,然後從頭開始掃描SC表,逐一查找與student表第一個元組的Sno相等的SC元組,找到後就將student中的第一個元組與該元組拼接起來,形成結果表中的一個元組。如果SC表上的Sno建立索引的話,就不用每次掃描SC表了。
3.2 自身連接
連接操作不僅可以在兩個表之間進行,還可以與自身進行連接,如下:
mysql> select * from course;
+-----+------------------+------+---------+
| Cno | Cname | Cpno | Ccredit |
+-----+------------------+------+---------+
| 1 | database | 5 | 3 |
| 2 | math | NULL | 2 |
| 3 | INFO SYS | 1 | 2 |
| 4 | operating system | 6 | 2 |
| 5 | data structure | 7 | 4 |
| 6 | data process | NULL | 4 |
| 7 | PASCAL | 6 | 4 |
+-----+------------------+------+---------+
表Course中的Cpno表示的是這門課程的先行課程,查詢一門課程的間接先修課如下:
mysql> select first.Cno,second.Cpno
-> from course first,course second
-> where first.Cpno=second.Cno;
+-----+------+
| Cno | Cpno |
+-----+------+
| 3 | 5 |
| 1 | 7 |
| 4 | NULL |
| 7 | NULL |
| 5 | 6 |
+-----+------+
通過Coruse表的內容可知,3的先行課是1,而1的先行課是5,所以3的間接先行課程是5,其它分析一樣。
3.3 外連接
先看一個例子:
mysql> select student.Sno,Sname,Ssex,Sdept,Cno,Grade
-> from student,sc where student.Sno=sc.Sno;//這裏用的是“等值連接”
+--------+-------+------+-------+-----+-------+
| Sno | Sname | Ssex | Sdept | Cno | Grade |
+--------+-------+------+-------+-----+-------+
| sa1211 | Lily | F | MA | 1 | 89 |
| sa1211 | Lily | F | MA | 2 | 90 |
| sa1211 | Lily | F | MA | 3 | 90 |
| sa1212 | ello | F | CS | 1 | 78 |
| sa1212 | ello | F | CS | 3 | 90 |
+--------+-------+------+-------+-----+-------+
mysql> select student.Sno,Sname,Ssex,Sdept,Cno,Grade
-> from student left join sc on (student.Sno=sc.Sno);//這裏用的是“外連接”中的“左外連接”
+--------+--------+------+-------+------+-------+
| Sno | Sname | Ssex | Sdept | Cno | Grade |
+--------+--------+------+-------+------+-------+
| sa1211 | Lily | F | MA | 1 | 89 |
| sa1211 | Lily | F | MA | 2 | 90 |
| sa1211 | Lily | F | MA | 3 | 90 |
| sa1212 | ello | F | CS | 1 | 78 |
| sa1212 | ello | F | CS | 3 | 90 |
| sa1213 | Hello | M | CS | NULL | NULL |
| sa1214 | Shely | F | IS | NULL | NULL |
| sa1215 | Shelly | F | CS | NULL | NULL |
| sa1216 | 趙三 | F | CS | NULL | NULL |
| sa1217 | 趙四 | F | CS | NULL | NULL |
| sa1218 | 張良 | F | CS | NULL | NULL |
| sa1219 | 張子房 | F | CS | NULL | NULL |
+--------+--------+------+-------+------+-------+
有時候想以student表為主體選出每個學生的基本情況和選課情況,如果用等值連接的話,則那些還未選課的同學的信息將不會展示出來,這時候“外連接”的作用突顯出來了,我們可以用“外連接”實現該功能,外連接分為左外連接和右外連接,假設有兩張表A和B,如果A左外連接B,則顯示的結果是以A為主體,A的信息將會完全展示,而B中沒有的信息將會顯示為NULL;右連接與之相對應,如果A右外連接B,則將會完全顯示B的信息。
3.4、復合條件連接
如果一個查詢語句中,where語句中有多個連接條件,則稱為“復合條件連接”。例如,查詢選修2號課程且成績在90分以上的所有學生:
select student.Sno,Sname
from student,sc
where student.Sno=sc.Sno and sc.Cno=‘2‘ and sc.grade>90;
4 嵌套查詢
如果將一個查詢塊嵌套在另一個查詢塊的where或having短語的條件中的查詢稱之為“嵌套查詢”,嵌套查詢有以下幾種情況:
4.1 帶有in的嵌套查詢
嵌套查詢中,子查詢的結果常是一個集合,為了完成嵌套查詢,常常先進行分步查詢,例如,查詢與“張子房”在同一個系學習的學生,可以分為以下步驟:
第一步:查詢“張子房”同學所在的系別,select Sdept from student where Sname="張子房";//結果為CS
第二步:查詢所有CS系的學生,select Sno,Sname,Sdept from student where Sdept="CS";
綜上,嵌套查詢語句可以是:
select Sno,Sname,Sdept
from student where Sdept in ( select Sdept from student where Sname="張子房");
這裏,子查詢的查詢條件不依賴於父查詢,稱之為“不相關子查詢”。
4.2 帶有比較運算符的子查詢
當子查詢返回的是單值時,可以用>,<,>=,<=,!=或<>等比較運算符進行相關條件的查詢。例如上句中,“張子房”只能在一個系別中,所以查詢語句還可以是:
select Sno,Sname,Sdept
from student where Sdept = ( select Sdept from student where Sname="張子房");
再比如,查詢每個學生超過他選修課程平均成績的課程號:
select Sno,Cno from SC x where grade >=(
select AVG(grade) from SC y where y.Sno=x.Sno);
這裏,內查詢是一個查詢所有選修課程平均成績的,至於是哪一個學生的平均成績是要看參數x.Sno的值,而該值是和父查詢相關的,所以,這類查詢稱之為相關子查詢。
4.3 帶有ANY(SOME)或ALL謂詞的子查詢
子查詢返回單值時可以用比較運算符,但返回多值是要用ANY(有的系統用SOME)或ALL修飾。其語義如下:
> ANY 大於子查詢中結果中的某個值
> ALL 大於子查詢中結果中的所有值
...
!=(或<>)ANY 不等於子查詢中結果中的某個值
!=(或<>)ALL 不等於子查詢中結果中的所有值
例如:查詢其他系中比計算機系中所有學生年齡都小的學生姓名和年齡:
select Sname,Sage from student where Sage < ALL( select Sage from student where Sdept="CS") and Sdept<>"CS";
4.4 帶有EXISTS謂詞的子查詢
帶有exists謂詞的子查詢不返回任何數據,只產生邏輯真“true”或邏輯假“false”。例如,查詢所有選修了1號課程的學生姓名:
select Sname from student where exists(select * from SC where Sno=student.Sno and Cno="1");
反之,查詢沒有選修1號課程的學生姓名:
select Sname from student where not exists(select * from SC where Sno=student.Sno and Cno="1");
再比如,查詢至少選修了學生200215選修的全部課程的學生號,其語義是這樣的:不存在這樣的課程y,學生200215選修了y,而學生x沒有選。sql語句如下:
select distinct Sno from SC x where not exists(
select * from SC y where y.Sno=‘200215‘ and not exists(
select * from SC z where z.Sno=x.Sno and z.Cno=y.Cno));//表示x與y選修相同課程的課程,加上前面的not exists,表示x不與y選修相同課程的課程;再加上最外層的not exists,表示不存在這樣的課程,y選修了,而x不與y選修相同的課程,雙重否定是肯定,表示,y選修的課程,x都有選擇。
5 集合查詢
select 語句的查詢結果是元組的集合,所以,多個select查詢可以進行集合操作,集合操作包括union(並)、intersect(交)、except(差)操作。這裏,參與集合操作的各查詢結果的列數必須相同,而且對應項的數據類型必須相同。
5.1 union操作,表示並操作,例如,查詢計算機系的學生以及年齡不大於19的學生。代碼如下:
select * from student where Sdept="CS"
union
select * from student where Sage<=19;
5.2 intersect操作,表示交操作,例如查詢既選修了課程1又選修了課程2的學生。代碼如下:
select Sno from SC where Cno=‘1‘
intersect
select Sno from SC where Cno=‘2‘;
5.3 except操作,表示差操作,例如查詢計算機系的學生與年齡不大於19歲的學生的差集:
select * from student where Sdept=‘CS‘
except
select * from student where Sage<=19;
其實,以上語句的效果就是查詢計算機系中,年齡大於19歲的學生:
select * from student where Sdept=‘CS‘ and Sage>19;
以上是數據查詢的總結...
數據庫之數據查詢