以前的SQL基礎1中已經介紹了部分Select的內容,可是,實際使用中select 還有不少其餘的用法,本文會再介紹部分select的其餘用法。mysql
建立2張表用於演示,表名分別爲student和class,後續也將繼續用這2張表演示,2張表的數據以下:sql
student表測試
class表優化
mysql> select class_no from student; +----------+ | class_no | +----------+ | 201801 | | 201901 | | 201901 | | 201902 | | 201902 | | 201902 | | 201902 | +----------+
可見,查詢結果中不少重複的狀況。spa
去重使用 DISTINCT 關鍵字便可code
mysql> select distinct class_no from student; +----------+ | class_no | +----------+ | 201801 | | 201901 | | 201902 | +----------+ 3 rows in set (0.00 sec)
條件查詢能夠有不少種組合,其中用 AND 或 OR鏈接不一樣的條件,同時能夠用in , not in , >、>=、 <、<=、 =等條件進行範圍查詢等blog
AND的意義至關於「且」,也就是AND先後的條件必須同時成立,例如:排序
查詢class_no爲201901 而且age>=22的學生索引
mysql> select * from student where age>=22 and class_no='201901'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | +----+----------+------+----------+ 1 row in set (0.00 sec)
OR意味着「或」,即OR先後條件中的一個知足條件及成立,例如:it
查詢student表中age>=24 後者班級號爲201801的學生
mysql> select * from student where age>=24 or class_no='201801'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 4 | 喬峯 | 30 | 201801 | | 7 | 杜甫 | 24 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec)
AND和OR的優先級順序是 AND大於OR,有括號的 先處理括號的 。即 AND和OR同時出現時,先處理AND 再與OR判斷,可是出現括號,有出現括號的先處理括號裏的。例如:
/** 沒有括號 先處理and 最後處理or **/ mysql> select * from student where age<23 and class_no='201902' or class_no='201801'; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 有括號時,先庫哦李括號裏的or,最後處理 外層的AND ** / mysql> select * from student where age<23 and (class_no='201902' or class_no='201801'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | +----+----------+------+----------+ 2 rows in set (0.00 sec)
建議: 實際使用時,若是嵌套的關係太多,當肯定須要先處理哪一個關係時建議都加上括號,已避免寫法錯誤致使結果與預期不一致。
IN 或 NOT IN的使用頻率也是很是高的,例如:
/** in **/ mysql> select * from student where class_no in ('201901','201902'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 蘇軾 | 20 | 201901 | | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飛 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec) /** not in **/ mysql> select * from student where class_no not in ('201901','201902'); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
排序使用order by來進行,能夠指定一個或多個字段進行排序,同時能夠指定升序(ASC,默認的是升序)或降序(DESC)。
/** 按照age升序排序 **/ mysql> select * from student order by age asc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 2 | 蘇軾 | 20 | 201901 | | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | | 8 | 岳飛 | 23 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 1 | 李白 | 25 | 201901 | | 4 | 喬峯 | 30 | 201801 | +----+----------+------+----------+ 7 rows in set (0.00 sec) /** 按照age降序排列 **/ mysql> select * from student order by age desc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | | 1 | 李白 | 25 | 201901 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飛 | 23 | 201902 | | 5 | 陳六 | 22 | 201902 | | 3 | 王維 | 21 | 201902 | | 2 | 蘇軾 | 20 | 201901 | +----+----------+------+----------+ 7 rows in set (0.00 sec) /** 先按照class_no升序,class_no 相同時按照age降序排列 **/ mysql> select * from student order by class_no,age desc; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | | 1 | 李白 | 25 | 201901 | | 2 | 蘇軾 | 20 | 201901 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飛 | 23 | 201902 | | 5 | 陳六 | 22 | 201902 | | 3 | 王維 | 21 | 201902 | +----+----------+------+----------+ 7 rows in set (0.00 sec)
注:當表的數據量較大時,建議排序字段上有索引。
分頁查詢在數據展現上是使用頻率很是高的功能之一,1其語法爲:
select field_names from tbname where filter order by oderby_fieldname limit offset,row_counts
其中 offset是偏移量,即以前遍歷了的數據量,row_counts指每頁的數據量。
例如,分頁遍歷其中一個表的記錄,每頁3條記錄,例如:
/** 首頁 **/ mysql> select * from student order by id limit 3*0,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 蘇軾 | 20 | 201901 | | 3 | 王維 | 21 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 第二頁 **/ mysql> select * from student order by id limit 3*1,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | | 5 | 陳六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | +----+----------+------+----------+ 3 rows in set (0.00 sec) /** 第三頁 **/ mysql> select * from student order by id limit 3*2,3; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 8 | 岳飛 | 23 | 201902 | +----+----------+------+----------+ 1 row in set (0.00 sec)
注: order by 的字段上必定要有索引,不然 可能遍歷額結果有重複,相關例子能夠自行測試。
不少狀況下,咱們都須要進行一些彙總類的操做,即聚合查詢。聚合查詢一般須要配合GROUP BY關鍵字進行分組聚合。下面使用幾種常見的聚合查詢操做。
count是指統計記錄條數。
/** 查看student表的記錄總數 **/ mysql> select count(*) from student; +----------+ | count(*) | +----------+ | 7 | +----------+ 1 row in set (0.00 sec) /** 查詢age大於24的記錄數 **/ mysql> select count(*) from student where age>=24; +----------+ | count(*) | +----------+ | 3 | +----------+ 1 row in set (0.00 sec)
/** 按照class_no分組統計,即查詢每一個班級的人數 **/
mysql> select class_no, count(*) from student group by class_no; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201801 | 1 | | 201901 | 2 | | 201902 | 4 | +----------+----------+ 3 rows in set (0.00 sec) /**查詢每一個班級的人數,同時按照人數降序排列 **/ mysql> select class_no, count(*) from student group by class_no order by count(*) desc ; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201902 | 4 | | 201901 | 2 | | 201801 | 1 | +----------+----------+ 3 rows in set (0.00 sec)
/**查詢每一個班級的人數,同時只返回人數大於1個的class_no及人數 **/
mysql> select class_no, count(*) from student group by class_no having count(*)>1 ; +----------+----------+ | class_no | count(*) | +----------+----------+ | 201901 | 2 | | 201902 | 4 | +----------+----------+ 2 rows in set (0.00 sec)
除了count的聚合操做外,還有min(最小)、max(最大) 、avg (平均)、sum(求和)等聚合操做,其操做和count相似。
例如:
mysql> select max(age),min(age),avg(age),sum(age) from student; +----------+----------+----------+----------+ | max(age) | min(age) | avg(age) | sum(age) | +----------+----------+----------+----------+ | 30 | 20 | 23.5714 | 165 | +----------+----------+----------+----------+ 1 row in set (0.00 sec)
當進行查詢下的時候 須要查詢的條件是另一個select語句的結果的時候能夠用到子查詢來處理。此時要用in、not in 、exists、not exists以及=、!=等。
例如:
/** 查詢存在於class表的student的記錄 **/ mysql> select * from student where class_no in (select class_no from class); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 蘇軾 | 20 | 201901 | | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飛 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec) /** 查詢不存在於class表的student的記錄 **/ mysql> select * from student where class_no not in (select class_no from class); +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
exists和not exists在此時(子查詢不存在null的狀況下)查詢結果是等價的(查詢效率有差別,且和數據量有關),對於此問題,各位能夠本身測一下。
當須要同時展現多個表的字段時,須要用錶鏈接的方式將多張表的字段在一個查詢中展現。
錶鏈接的方式從大類上來講能夠分爲內鏈接和外鏈接。
內鏈接是查詢2張表同時存在的記錄,即兩張表的交集。
例如:
/** 同時查詢兩張表中class_no 相同的student及class表的全部字段內容 **/ mysql> select * from student a,class b -> where a.class_no=b.class_no; +----+----------+------+----------+----------+--------------+------------------+ | id | stu_name | age | class_no | class_no | class_name | location | +----+----------+------+----------+----------+--------------+------------------+ | 1 | 李白 | 25 | 201901 | 201901 | 2019級01班 | 博學北樓A401 | | 2 | 蘇軾 | 20 | 201901 | 201901 | 2019級01班 | 博學北樓A401 | | 3 | 王維 | 21 | 201902 | 201902 | 2019級02班 | 博學北樓B401 | | 5 | 陳六 | 22 | 201902 | 201902 | 2019級02班 | 博學北樓B401 | | 7 | 杜甫 | 24 | 201902 | 201902 | 2019級02班 | 博學北樓B401 | | 8 | 岳飛 | 23 | 201902 | 201902 | 2019級02班 | 博學北樓B401 | +----+----------+------+----------+----------+--------------+------------------+ 6 rows in set (0.00 sec)
注:
a) 例子中是列舉出全部字段,全部能夠用* ,當須要列出指定字段時,能夠列出指定字段名展現,經過表名.字段名的方式列出
b) 內鏈接的寫法能夠向上述例子中那樣,也能夠用inner join ... on...這種方式來寫,其中inner能夠省略,例如:
mysql> select a.stu_name,b.class_name from student a inner join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | +----------+--------------+ 6 rows in set (0.00 sec)
c) in能夠用內鏈接的方式來改寫,尤爲是多層子查詢時,這也是SQL優化中給的一種方案。例如以前in例子就能夠改寫爲:
mysql> select distinct a.* from student a inner join class b on a.class_no=b.class_no; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 1 | 李白 | 25 | 201901 | | 2 | 蘇軾 | 20 | 201901 | | 3 | 王維 | 21 | 201902 | | 5 | 陳六 | 22 | 201902 | | 7 | 杜甫 | 24 | 201902 | | 8 | 岳飛 | 23 | 201902 | +----+----------+------+----------+ 6 rows in set (0.00 sec)
外鏈接分爲左鏈接和右鏈接,其中:
a) 左鏈接是指包含左邊表中的記錄,即便左表中含有和右表匹配不上的記錄也會保留。
b) 右鏈接是指包含右邊表中的記錄,即便右表中含有和左表匹配不上的記錄也會保留。
例如:
/** 左鏈接 **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | | 喬峯 | NULL | /** 改記錄的class_no不存在與右表中 **/ +----------+--------------+ 7 rows in set (0.00 sec) /** 右鏈接 **/ mysql> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | +----------+--------------+
注: 也可使用外鏈接來改寫not in ,例如以前not in的例子能夠按照以下方式改寫:
mysql> select distinct a.* from student a left join class b on a.class_no=b.class_no where b.class_no is null; +----+----------+------+----------+ | id | stu_name | age | class_no | +----+----------+------+----------+ | 4 | 喬峯 | 30 | 201801 | +----+----------+------+----------+ 1 row in set (0.00 sec)
記錄聯合是指將多個查詢結果合併到一塊兒展現,須要用到UNION 、UNION ALL 關鍵字,其中UNION ALL不對多個查詢的結果去重,所有展現出來(即便查詢結果徹底相同),union 會對結果中的重複記錄進行去重後展現。
例如:
/** union all **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no -> union all -> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | | 喬峯 | NULL | | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | +----------+--------------+ 13 rows in set (0.00 sec) /** union **/ mysql> select a.stu_name,b.class_name from student a left join class b on a.class_no=b.class_no -> union -> select a.stu_name,b.class_name from student a right join class b on a.class_no=b.class_no; +----------+--------------+ | stu_name | class_name | +----------+--------------+ | 李白 | 2019級01班 | | 蘇軾 | 2019級01班 | | 王維 | 2019級02班 | | 陳六 | 2019級02班 | | 杜甫 | 2019級02班 | | 岳飛 | 2019級02班 | | 喬峯 | NULL | +----------+--------------+ 7 rows in set (0.00 sec)