MySQL聚合查詢案例講解
1、前言
前面的內(nèi)容已經(jīng)把基礎(chǔ)的增刪改查介紹的差不多了,也介紹了表的相關(guān)約束, 從本期開始往后的內(nèi)容,就更加復(fù)雜了,更多的是一些復(fù)雜的查詢 SQL.
本期雖然是講述聚合查詢相關(guān)知識,但是這里補(bǔ)充一個(gè)知識點(diǎn),如何將查詢結(jié)果插入到另一個(gè)表中呢?
2、插入查詢結(jié)果
查詢還是用的比較多的,對于查詢到的數(shù)據(jù),能不能也給保存下來呢?也就是把查詢的結(jié)果插入到另一張表中。
案例:創(chuàng)建一張學(xué)生表,表中有 id,name,sex,java,python 這些字段,現(xiàn)需要把 java 成績超過 90 的學(xué)生復(fù)制進(jìn) java_result 表,復(fù)制的字段為 name,java。
進(jìn)行上述操作之前,我們需要創(chuàng)建一個(gè)學(xué)生表并準(zhǔn)備好相關(guān)的數(shù)據(jù):
create table student ( id int primary key, name varchar(20), sex varchar(1), java float(5, 2) ); insert into student value (1, '張三', '男', 92.1), (2, '小紅', '女', 88.2), (3, '趙六', '男', 83.4), (4, '王五', '男', 93.3), (5, '小美', '女', 96.0);
有了學(xué)生表之后,我們要把 name,java 這兩個(gè)字段的查詢結(jié)果復(fù)制到 java_result 這個(gè)表中,這里我們注意,要求查詢結(jié)果的臨時(shí)表的列數(shù)和列的類型,要和 java_result 這里匹配,所以接下來我們就來創(chuàng)建 java_result 這張表:
create table java_result ( name varchar(20), java float(5, 2) );
創(chuàng)建好 java_result 這張表之后,就要查詢 student 表中 name java 兩個(gè)字段,并且 java > 90,將滿足上述條件的查詢結(jié)果,插入到 java_result 表中?。?/p>
insert into java_result select name, java from student where java > 90; -- Query OK, 3 rows affected (0.00 sec) -- Records: 3 Duplicates: 0 Warnings: 0
select * from java_result; +--------+-------+ | name | java | +--------+-------+ | 張三 | 92.10 | | 王五 | 93.30 | | 小美 | 96.00 | +--------+-------+ -- 3 rows in set (0.00 sec)
這樣我們就發(fā)現(xiàn),已經(jīng)將 student 表中 name 和 java 字段滿足 > 90 的數(shù)據(jù)已經(jīng)全部插入成功了!
3、聚合查詢
前面我們接觸過的 帶表達(dá)式查詢 都是列和列之間進(jìn)行運(yùn)算的,看哪一列滿足了這個(gè)條件。
而現(xiàn)在要介紹的聚合查詢,就是針對 行和行 之間進(jìn)行運(yùn)算的!
3.1 聚合函數(shù)
進(jìn)行聚合查詢,需要搭配聚合函數(shù),下面介紹的函數(shù)都是 SQL 中內(nèi)置的一組函數(shù),我們先來簡單的認(rèn)識下:
函數(shù) | 解釋 |
---|---|
COUNT([DISTINCT] expr) | 返回查詢到的數(shù)據(jù)的數(shù)量 |
SUM([DISTINCT] expr) | 返回查詢到的數(shù)據(jù)的總和,不是數(shù)字無意義 |
AVG([DISTINCT] expr) | 返回查詢到的數(shù)據(jù)的平均值,不是數(shù)字無意義 |
MAX([DISTINCT] expr) | 返回查詢到的數(shù)據(jù)的最大值,不是數(shù)字無意義 |
MIN([DISTINCT] expr) | 返回查詢到的數(shù)據(jù)的最小值,不是數(shù)字沒有意義 |
下面我們就來演示一下上述的聚合函數(shù)的簡單使用,在使用之前,我們需要有一張表,并且有相應(yīng)的數(shù)據(jù):
select * from student; +----+--------+------+-------+ | id | name | sex | java | +----+--------+------+-------+ | 1 | 張三 | 男 | 92.10 | | 2 | 小紅 | 女 | 88.20 | | 3 | 趙六 | 男 | 83.40 | | 4 | 王五 | 男 | 93.30 | | 5 | 小美 | 女 | 96.00 | | 6 | 李四 | 男 | NULL | +----+--------+------+-------+ -- 6 rows in set (0.00 sec)
下面我們就針對上述這張表,來使用下上述的聚合函數(shù)。
3.1.1 count
● 求出 student 表中有多少同學(xué)
select count(*) from student; +----------+ | count(*) | +----------+ | 6 | +----------+ -- 1 row in set (0.00 sec)
這個(gè)操作就相當(dāng)于先進(jìn)行 select * ,然后針對返回的結(jié)果,在進(jìn)行 count 運(yùn)算,求結(jié)果集合的行數(shù). 注意:此處如果有一列的數(shù)據(jù)全是 null,也會算進(jìn)去!(因?yàn)槭轻槍?*)
此處這里的 count() 括號中,不一定寫 *,可以寫成任意的列明/表達(dá)式,所以我們可以針對 name 來統(tǒng)計(jì)人數(shù):
select count(name) from student; +-------------+ | count(name) | +-------------+ | 6 | +-------------+ -- 1 row in set (0.00 sec)
● 統(tǒng)計(jì)有多少人有 java 考試成績
select count(java) from student; +-------------+ | count(java) | +-------------+ | 5 | +-------------+ -- 1 row in set (0.00 sec)
這里我們看到了,由于 count 是針對 java 字段進(jìn)行統(tǒng)計(jì),而 李四 那一條數(shù)據(jù)中,java 為 null,前面我們學(xué)習(xí)過,null 與任何值計(jì)算都是 null,所以統(tǒng)計(jì)的時(shí)候,就把 null 給去掉了。
● 統(tǒng)計(jì) java 成績大于90分的人數(shù)
select count(java) from student where java > 90; +-------------+ | count(java) | +-------------+ | 3 | +-------------+ -- 1 row in set (0.00 sec)
這里我們要弄清楚,count() 這個(gè)括號中,是針對你要針對的那一列,針對不同列,不同的條件,就會有不同的結(jié)果,對于 count 的演示就到這里。
注意:count 和 () 之間不能有空格,必須緊挨著,在 Java 中函數(shù)名和() 之間是可以有空格的,但很少人會這樣寫。
3.1.2 sum
這個(gè)聚合函數(shù),就是把指定列的所有行進(jìn)行相加得到的結(jié)果,要求這個(gè)列得是數(shù)字,不能是字符串/日期。
● 求出學(xué)生表中 java 考試分?jǐn)?shù)總和
select sum(java) from student; +-----------+ | sum(java) | +-----------+ | 453.00 | +-----------+ -- 1 row in set (0.01 sec)
雖然我們表中有 java 字段這列中有 null 值,前面了解到 null 與任何值運(yùn)算都是 null,但是這里的 sum 函數(shù)會避免這種情況發(fā)生。
當(dāng)然在后面也可也帶上 where 條件,這里就不做過多演示了。
3.1.3 avg
● 求班級中 java 的平均分
select avg(java) from student; +-----------+ | avg(java) | +-----------+ | 90.600000 | +-----------+ -- 1 row in set (0.00 sec)
當(dāng)前只是針對某一列進(jìn)行平均運(yùn)算,如果有兩門課程,求每個(gè)學(xué)生總分的平均分呢?
select avg(java + python) from student;
這里每次查詢結(jié)果都只有一列,能否把兩個(gè)聚合函數(shù)一起使用呢?
select sum(java), avg(java) as '平均分' from student; +-----------+-----------+ | sum(java) | 平均分 | +-----------+-----------+ | 453.00 | 90.600000 | +-----------+-----------+ -- 1 row in set (0.00 sec)
這里我們能發(fā)現(xiàn)一個(gè)細(xì)節(jié),使用聚合函數(shù)查詢,字段也是可以取別名的。
3.1.4 max 和 min
● 求出 java 考試分?jǐn)?shù)的最高分和最低分
select max(java) as '最高分', min(java) as '最低分' from student; +-----------+-----------+ | 最高分 | 最低分 | +-----------+-----------+ | 96.00 | 83.40 | +-----------+-----------+ -- 1 row in set (0.00 sec)
上述就是聚合函數(shù)最基礎(chǔ)的用法了, 但是在實(shí)際中也可能會有更復(fù)雜的情況,比如需要按照某某進(jìn)行分組查詢,這就需要搭配 GROUP BY 字句了。
4、GROUP BY 子句
select 中使用 group by 自居可以對指定列進(jìn)行分組查詢,但是需要滿足指定分組的字段必須是 "分組依據(jù)字段",其他字段若想出現(xiàn)在 select 中,則必須包含在聚合函數(shù)中。
這里我們構(gòu)造出一張薪水表 salary:
create table salary ( id int primary key, name varchar(20), role varchar(20), income int ); insert into salary value (1, '麻花疼', '老板', 5000000), (2, '籃球哥', '程序猿', 3000), (3, '歪嘴猴', '經(jīng)理', 20000), (4, '多嘴鳥', '經(jīng)理', 25000), (5, '雷小君', '老板', 3000000), (6, '阿紫姐', '程序猿', 5000);
像上述的情況,如果要查平均工資,那公平嗎???
select avg(income) from salary; +--------------+ | avg(income) | +--------------+ | 1342166.6667 | +--------------+ -- 1 row in set (0.00 sec)
那籃球哥的月薪連平均下來的零頭都不到,所以這樣去求平均工資是毫無意義的,真正有意義的是啥呢?求老板這個(gè)職位的平均工資,以及經(jīng)理這個(gè)職位的平均工資,及程序猿這個(gè)職位的平均工資,通俗來說,就是按照 role 這個(gè)字段進(jìn)行分組。每一組求平均工資:
select role, avg(income) from salary group by role; +-----------+--------------+ | role | avg(income) | +-----------+--------------+ | 程序猿 | 4000.0000 | | 經(jīng)理 | 22500.0000 | | 老板 | 4000000.0000 | +-----------+--------------+ -- 3 rows in set (0.00 sec)
這就也就是把 role 這一列,值相同的行給分成了一組,然后計(jì)算平均值,也是針對每個(gè)分組,分別計(jì)算。
在 MySQL 中,這里得到的查詢結(jié)果臨時(shí)表,如果沒有 order by 指定列排序,這里的順序是不可預(yù)期的,當(dāng)然也可以手動指定排序,比如最終結(jié)果按照平均工資降序排序:
select role, avg(income) from salary group by role order by avg(income) desc; +-----------+--------------+ | role | avg(income) | +-----------+--------------+ | 老板 | 4000000.0000 | | 經(jīng)理 | 22500.0000 | | 程序猿 | 4000.0000 | +-----------+--------------+ -- 3 rows in set (0.00 sec)
如果不帶聚合函數(shù)的普通查詢,能否可行呢?這里如果你沒有修改任何配置文件,是不可行的,記住千萬不能把前面的 order by 與 group by 弄混!
5、HAVING 關(guān)鍵字
分組查詢也是可以指定條件的,具體三種情況:
- 先篩選,再分組(where)
- 先分組,再篩選(having)
- 分組前分組后都指定條件篩選(where 和 having 結(jié)合使用)
如何理解上述三條的含義呢? 這里我們舉幾個(gè)例子就很好理解了:
● 籃球哥月薪 3000 實(shí)在是太低了,簡直給程序猿崗位拖后腿,干脆求平均工資時(shí)去掉籃球哥的月薪數(shù)據(jù)。
select role, avg(income) from salary where name != '籃球哥' group by role; +-----------+--------------+ | role | avg(income) | +-----------+--------------+ | 程序猿 | 5000.0000 | | 經(jīng)理 | 22500.0000 | | 老板 | 4000000.0000 | +-----------+--------------+ -- 3 rows in set (0.00 sec)
這樣求出來的平均值就不包含籃球哥的月薪數(shù)據(jù)了,這就是先篩選,再分組。
● 還是查詢每個(gè)崗位的平均工資,但是除去平均月薪在 10w 以上的崗位,不能讓籃球哥眼紅!
select role, avg(income) from salary group by role having avg(income) < 100000; +-----------+-------------+ | role | avg(income) | +-----------+-------------+ | 程序猿 | 4000.0000 | | 經(jīng)理 | 22500.0000 | +-----------+-------------+ -- 2 rows in set (0.00 sec)
這樣一來就只保留了平均月薪小于 10w 的崗位了,很明顯這個(gè)平均值是在分組之后才算出來的,這也就是先分組,再篩選。
這里 having 也能加上邏輯運(yùn)算符,具體感興趣的小伙伴可以自行下來嘗試一下,好比如你想要拿好 offer,就得技術(shù)過關(guān),還能加班!
至于第三種分組前后都需要篩選,就是把上述倆例子結(jié)合起來,這里就不多贅述了!
到此這篇關(guān)于MySQL聚合查詢的文章就介紹到這了,更多相關(guān)mysql聚合查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SQL算術(shù)運(yùn)算符之加法、減法、乘法、除法和取模的用法例子
算術(shù)運(yùn)算符主要用于數(shù)學(xué)運(yùn)算,其可以連接運(yùn)算符前后的兩個(gè)數(shù)值或表達(dá)式,對數(shù)值或表達(dá)式進(jìn)行加(+)、減(-)、乘(*)、除(/)和取模(%)運(yùn)算,下面這篇文章主要給大家介紹了關(guān)于SQL算術(shù)運(yùn)算符之加法、減法、乘法、除法和取模用法的相關(guān)資料,需要的朋友可以參考下2024-03-03centos7.2下安裝mysql5.7數(shù)據(jù)庫的命令詳解
這篇文章主要介紹了centos7.2下安裝mysql5.7數(shù)據(jù)庫,文中給出了所有的命令,按照命令執(zhí)行就會安裝上 ,需要的朋友可以參考下2019-07-07MySQL group by和left join并用解決方式
這篇文章主要介紹了MySQL group by和left join并用解決方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12MySQL錯誤TIMESTAMP column with CURRENT_TIMESTAMP的解決方法
這篇文章主要介紹了MySQL錯誤TIMESTAMP column with CURRENT_TIMESTAMP的解決方法,需要的朋友可以參考下2014-06-06