一 單表查詢的語法
#查詢數據的本質:mysql會到你本地的硬盤上找到對應的文件,然后打開文件,按照你的查詢條件來找出你需要的數據。下面是完整的一個單表查詢的語法
select * from,這個select * 指的是要查詢所有字段的數據。
SELECT distinct 字段1,字段2... FROM 庫名.表名 #from后面是說從庫的某個表中去找數據,mysql會去找到這個庫對應的文件夾下去找到你表名對應的那個數據文件,找不到就直接報錯了,找到了就繼續后面的操作 WHERE 條件 #從表中找符合條件的數據記錄,where后面跟的是你的查詢條件 GROUP BY field(字段) #分組 HAVING 篩選 #過濾,過濾之后執行select后面的字段篩選,就是說我要確定一下需要哪個字段的數據,你查詢的字段數據進行去重,然后在進行下面的操作 ORDER BY field(字段) #將結果按照后面的字段進行排序 LIMIT 限制條數 #將最后的結果加一個限制條數,就是說我要過濾或者說限制查詢出來的數據記錄的條數
關於上面這些內容,我們在下面一個一個的來詳細解釋
二 關鍵字的執行優先級(重點)
重點中的重點:關鍵字的執行優先級 from where group by having select distinct order by limit
1.找到表:from
2.拿着where指定的約束條件,去文件/表中取出一條條記錄
3.將取出的一條條記錄進行分組group by,如果沒有group by,則整體作為一組
4.將分組的結果進行having過濾
5.執行select
6.去重
7.將結果按條件排序:order by
8.限制結果的顯示條數
詳細見:https://www.cnblogs.com/clschao/articles/9995517.html
三 簡單查詢
#我們來創建一個員工表,然后對員工表進行一個簡單的查詢,來看一下效果,下面是員工表的字段
company.employee 員工id id int 姓名 emp_name varchar 性別 sex enum 年齡 age int 入職日期 hire_date date 崗位 post varchar 職位描述 post_comment varchar 薪水 salary double 辦公室 office int 部門編號 depart_id int #創建表 create table employee( id int not null unique auto_increment, name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一個部門一個屋子 depart_id int ); #查看表結構 mysql> desc employee; +--------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(3) unsigned | NO | | 28 | | | hire_date | date | NO | | NULL | | | post | varchar(50) | YES | | NULL | | | post_comment | varchar(100) | YES | | NULL | | | salary | double(15,2) | YES | | NULL | | | office | int(11) | YES | | NULL | | | depart_id | int(11) | YES | | NULL | | +--------------+-----------------------+------+-----+---------+----------------+ #插入記錄 #三個部門:教學,銷售,運營 insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values ('egon','male',18,'20170301','老男孩駐沙河辦事處外交大使',7300.33,401,1), #以下是教學部,全都是老師 ('alex','male',78,'20150302','teacher',1000000.31,401,1), ('wupeiqi','male',81,'20130305','teacher',8300,401,1), ('yuanhao','male',73,'20140701','teacher',3500,401,1), ('liwenzhou','male',28,'20121101','teacher',2100,401,1), ('jingliyang','female',18,'20110211','teacher',9000,401,1), ('jinxin','male',18,'19000301','teacher',30000,401,1), ('成龍','male',48,'20101111','teacher',10000,401,1), ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是銷售部門 ('丫丫','female',38,'20101101','sale',2000.35,402,2), ('丁丁','female',18,'20110312','sale',1000.37,402,2), ('星星','female',18,'20160513','sale',3000.29,402,2), ('格格','female',28,'20170127','sale',4000.33,402,2), ('張野','male',28,'20160311','operation',10000.13,403,3), #以下是運營部門 ('程咬金','male',18,'19970312','operation',20000,403,3), ('程咬銀','female',18,'20130311','operation',19000,403,3), ('程咬銅','male',18,'20150411','operation',18000,403,3), ('程咬鐵','female',18,'20140512','operation',17000,403,3) ; #ps:如果在windows系統中,插入中文字符,select的結果為空白,可以將所有字符編碼統一設置成gbk
查詢操作:
簡單查詢 SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id FROM employee; SELECT * FROM employee; #不推薦用* ,查詢的時候*的效率低,至於為什么低,后面會講到,先知道一下就行了 SELECT name,salary FROM employee; #避免重復DISTINCT
SELECT post FROM employee;#直接這樣查詢我們會看到很多重復的內容,我只想看一下有哪些職位,那么多重復的內容是沒用的,所以我們加一個去重的功能,叫做distinct
SELECT DISTINCT post FROM employee; #對查詢出來的記錄進行去重,如果post職位有重復的,就會被剔除,剩下不重復的內容,注意,因為我們查詢出來的記錄里面只有一個字段post,才會根據post來進行去重
SELECT DISTINCT post,salary FROM employee;#但是如果這樣寫,你會發現,貌似沒有起到根據post來去重的效果,因為你的去重條件變成了post和salary兩個字段的數據,只有他倆合起來是一個重復記錄的時候才會去重
看一下下面這兩句的效果就明白了:注意一點,使用distinct對記錄進行去重的時候,distinct必須寫在所有查詢字段的前面,不然會報錯,當然有些特別的用法可以結合着寫到字段的中間或者后面,這個后面學到了我們再說
select post,sex from employee;
select distinct post,sex from employee;
#通過四則運算查詢 SELECT name, salary*12 FROM employee; #查詢每個人的年薪,月薪我們有記錄,查年薪呢?簡單的乘以12就可以了,from 庫.表的時候,我們已經通過use 庫名;來指定了庫了,所以from的時候直接寫from 表,就行了 #你會發現,結果是出來了,但是我們的那個薪資的字段名變成了salary*12,是因為我們通過查詢語句查詢出來的也是一張表,但是這個表是不是內存當中的一個虛擬表,並不是我們硬盤中存的那個完整的表,對吧,虛擬表是不是也有標題和記錄啊,既然是一個表,我們是可以指定這個虛擬表的標題的,通過as+新字段名來指定
SELECT name, salary*12 AS Annual_salary FROM employee; #as + 新字段名,就是起一個別名的意思,上面的那個salary*12的字段名也是一個別名,只不過不直觀,是mysql自動給你寫上的 SELECT name, salary*12 Annual_salary FROM employee; #除了乘法以外,加減乘除都是可以的
#自定義顯示格式,自己規定查詢結果的顯示格式 CONCAT() 函數用於連接字符串 SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary #我想讓name這個字段顯示的字段名稱是中文的姓名,讓salary*12顯示的是中文的年薪, FROM employee;#看結果:通過結果你可以看出,這個concat就是幫我們做字符串拼接的,並且拼接之后的結果,都在一個叫做Annual_salary的字段中了
+---------------------------------------+
| Annual_salary |
+---------------------------------------+
| 姓名: egon 年薪: 87603.96 |
| 姓名: alex 年薪: 12000003.72 |
| 姓名: wupeiqi 年薪: 99600.00 |
| 姓名: yuanhao 年薪: 42000.00 |
.....
+---------------------------------------+
SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary,CONCAT('性別:',sex) from employee;#還可以這樣分成兩列
CONCAT_WS() 第一個參數為分隔符來進行字符串拼接 SELECT CONCAT_WS(':',name,salary*12) AS Annual_salary #通過冒號來將name和salary連接起來 FROM employee; #上面這個效果我們也可以通過concat來實現:SELECT CONCAT(name,':',salary*12) AS Annual_salary from employee; 結合CASE語句:結合條件來對查詢的結果進行一些加工操作 SELECT ( CASE WHEN NAME = 'egon' THEN NAME WHEN NAME = 'alex' THEN CONCAT(name,'_BIGSB') ELSE concat(NAME, 'SB') END ) as new_name,sex FROM employee;
#看結果:
+--------------+--------+
| new_name | sex |
+--------------+--------+
| egon | male |
| alex_BIGSB | male |
| wupeiqiSB | male |
| yuanhaoSB | male |
| liwenzhouSB | male |
| jingliyangSB | female |
| jinxinSB | male |
| 成龍SB | male |
...
+--------------+
簡單查詢就結束了,我們做一下練習,然后繼續學習我們上面列舉完整查詢語句中的其他內容。
小練習:
1 查出所有員工的名字,薪資,格式為 <名字:egon> <薪資:3000> 2 查出所有的崗位(去掉重復) 3 查出所有員工名字,以及他們的年薪,年薪的字段名為annual_year

select concat('<名字:',name,'> ','<薪資:',salary,'>') from employee; select distinct depart_id from employee; select name,salary*12 annual_salary from employee;
四 WHERE約束
where語句中可以使用:
之前我們用where 后面跟的語句是不是id=1這種類型的啊,用=號連接的,除了=號外,還能使用其他的,看下面:
1. 比較運算符:> < >= <= <> !=
2. between 80 and 100 值在80到100之間
3. in(80,90,100) 值是80或90或100
4. like 'egon%'
pattern可以是%或_,
%表示任意多字符
_表示一個字符
5. 邏輯運算符:在多個條件直接可以使用邏輯運算符 and or not
#1:單條件查詢 SELECT name FROM employee WHERE post='sale'; #注意優先級,我們說where的優先級是不是比select要高啊,所以我們的順序是先找到這個employee表,然后按照post='sale'的條件,然后去表里面select數據 #2:多條件查詢 SELECT name,salary FROM employee WHERE post='teacher' AND salary>10000; #3:關鍵字BETWEEN AND 寫的是一個區間 SELECT name,salary FROM employee WHERE salary BETWEEN 10000 AND 20000; #就是salary>=10000 and salary<=20000的數據 SELECT name,salary FROM employee WHERE salary NOT BETWEEN 10000 AND 20000; #加個not,就是不在這個區間內,薪資小於10000的或者薪資大於20000的,注意沒有等於, #4:關鍵字IS NULL(判斷某個字段是否為NULL不能用等號,需要用IS) 判斷null只能用is SELECT name,post_comment FROM employee WHERE post_comment IS NULL; SELECT name,post_comment FROM employee WHERE post_comment IS NOT NULL; SELECT name,post_comment FROM employee WHERE post_comment=''; 注意''是空字符串,不是null,兩個是不同的東西,null是啥也沒有,''是空的字符串的意思,是一種數據類型,null是另外一種數據類型 ps: 執行 update employee set post_comment='' where id=2; 再用上條查看,就會有結果了 #5:關鍵字IN集合查詢 SELECT name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ; #這樣寫是不是太麻煩了,寫一大堆的or,下面我們用in這個簡單的寫法來搞 SELECT name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ; SELECT name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ; #6:關鍵字LIKE模糊查詢,模糊匹配,可以結合通配符來使用 通配符’%’ #匹配任意所有字符 SELECT * FROM employee WHERE name LIKE 'eg%'; 通配符’_’ #匹配任意一個字符 SELECT * FROM employee WHERE name LIKE 'al__'; #注意我這里寫的兩個_,用1個的話,匹配不到alex,因為al后面還有兩個字符ex。
where條件咱們就說完了,這個where條件到底怎么運作的,我們來說一下:我們以select id,name,age from employee where id>7;這個語句來說一下
首先先找到employee表,找到這個表之后,mysql會拿着where后面的約束條件去表里面找符合條件的數據,然后遍歷你表中所有的數據,查看一下id是否大於7,逐條的對比,然后只要發現id比7大的,它就會把這一整條記錄給select,但是select說我只拿id、name、age這個三個字段里面的數據,然后就打印了這三個字段的數據,然后where繼續往下過濾,看看id是不是還有大於7的,然后發現一個符合條件的就給select一個,然后重復這樣的事情,直到把數據全部過濾一遍才會結束。這就是where條件的一個工作方式。
然后我們可以來做一些小練習:
1. 查看崗位是teacher的員工姓名、年齡 2. 查看崗位是teacher且年齡大於30歲的員工姓名、年齡 3. 查看崗位是teacher且薪資在9000-1000范圍內的員工姓名、年齡、薪資 4. 查看崗位描述不為NULL的員工信息 5. 查看崗位是teacher且薪資是10000或9000或30000的員工姓名、年齡、薪資 6. 查看崗位是teacher且薪資不是10000或9000或30000的員工姓名、年齡、薪資 7. 查看崗位是teacher且名字是jin開頭的員工姓名、年薪

select name,age from employee where post = 'teacher'; select name,age from employee where post='teacher' and age > 30; select name,age,salary from employee where post='teacher' and salary between 9000 and 10000; select * from employee where post_comment is not null; select name,age,salary from employee where post='teacher' and salary in (10000,9000,30000); select name,age,salary from employee where post='teacher' and salary not in (10000,9000,30000); select name,salary*12 from employee where post='teacher' and name like 'jin%';
五 分組查詢:GROUP BY
1、 什么是分組?為什么要分組?
#1、首先明確一點:分組發生在where之后,即分組是基於where之后得到的記錄而進行的 #2、分組指的是:將所有記錄按照某個相同字段進行歸類,比如針對員工信息表的職位分組,或者按照性別進行分組等 #3、為何要分組呢?是因為我們有時候會需要以組為單位來統計一些數據或者進行一些計算的,對不對,比方說下面的幾個例子 取每個部門的最高工資 取每個部門的員工數 取男人數和女人數 小竅門:‘每’這個字后面的字段,就是我們分組的依據,只是個小竅門,但是不能表示所有的情況,看上面第三個分組,沒有'每'字,這個就需要我們通過語句來自行判斷分組依據了 我們能用id進行分組嗎,能,但是id是不是重復度很低啊,基本沒有重復啊,對不對,這樣的字段適合做分組的依據嗎?不適合,對不對,依據性別分組行不行,當然行,因為性別我們知道,是不是就兩種啊,也可能有三種是吧,這個重復度很高,對不對,分組來查的時候才有更好的意義 #4、大前提: 可以按照任意字段分組,但是分組完畢后,比如group by post,只能查看post字段,如果想查看組內信息,需要借助於聚合函數
#注意一點,在查詢語句里面select 字段 from 表,這幾項是必須要有的,其他的什么where、group by等等都是可有可無的
來,我們來測試一下:
mysql> select * from employee group by post; +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | | 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 | | 2 | alex | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 | | 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 | +----+--------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ 4 rows in set (0.06 sec) 通過結果可以看出,如果直接通過post部門字段來進行分組,默認拿到的結果都是每組的第一條數據
但是你想,我們分組的意義是什么,是不是說通過分組來統計一下整個組的情況啊,不再是看某個人單獨的情況了,對不對,並且將來你在這樣進行直接分組查詢的時候,可能因為你們公司設置的mysql的環境不同,而查不到數據,我們可以看到,我們現在仍然可以查詢出來數據,但是如果我們在sql_mode中添加了下面的only_full_group_by這個mode,那么我們在直接分組查詢,就無法得到數據了,只能得到字段名
並且設置了sql_mode為only_full_group_by之后,select *,就不行了,會直接報錯,只能select post ,post是你分組的那個字段
2、 ONLY_FULL_GROUP_BY
#查看MySQL 5.7默認的sql_mode如下: mysql> select @@global.sql_mode; ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION #!!!注意 ONLY_FULL_GROUP_BY的語義就是確定select target list中的所有列的值都是明確語義,簡單的說來,在ONLY_FULL_GROUP_BY模式下,target list中的值要么是來自於聚集函數的結果,要么是來自於group by list中的表達式的值。 #設置sql_mole如下操作(我們可以去掉ONLY_FULL_GROUP_BY模式): mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
看一下測試:
mysql> select @@global.sql_mode; +-------------------+ | @@global.sql_mode | +-------------------+ | | +-------------------+ 1 row in set (0.00 sec) mysql> select * from emp group by post; +----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+ | 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | | 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 | | 2 | alex | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 | | 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 | +----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+ 4 rows in set (0.00 sec) #由於沒有設置ONLY_FULL_GROUP_BY,於是也可以有結果,默認都是組內的第一條記錄,但其實這是沒有意義的 mysql> set global sql_mode='ONLY_FULL_GROUP_BY'; Query OK, 0 rows affected (0.00 sec) mysql> quit #設置成功后,一定要退出,然后重新登錄方可生效 Bye mysql> use db1; Database changed mysql> select * from emp group by post; #報錯 ERROR 1055 (42000): 'db1.emp.id' isn't in GROUP BY #意思是告訴你,你select后面取的字段必須在你的group by后面的字段里面才行
mysql> select post,count(id) from emp group by post; #只能查看分組依據和使用聚合函數 +----------------------------+-----------+ | post | count(id) | +----------------------------+-----------+ | operation | 5 | | sale | 5 | | teacher | 7 | | 老男孩駐沙河辦事處外交大使 | 1 | +----------------------------+-----------+ 4 rows in set (0.00 sec)
因為一般分組之后,我們再考慮其中一條數據就沒有什么意義了,所以一般我們都會在這種模式下進行分組,下面我們在看看group by,下面的內容
3、 GROUP BY
單獨使用GROUP BY關鍵字分組 SELECT post FROM employee GROUP BY post; 注意:我們按照post字段分組,那么select查詢的字段只能是post,想要獲取組內的其他相關信息,需要借助函數 GROUP BY關鍵字和GROUP_CONCAT()函數一起使用,比如說我想按部門分組,每個組有哪些員工,都顯示出來,怎么搞 SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照崗位分組,並查看組內所有成員名,通過逗號拼接在一起 SELECT post,GROUP_CONCAT(name,':',salary) as emp_members FROM employee GROUP BY post; GROUP BY一般都會與聚合函數一起使用,聚合是什么意思:聚合就是將分組的數據聚集到一起,合並起來搞事情,拿到一個最后的結果 select post,count(id) as count from employee group by post;#按照崗位分組,並查看每個組有多少人,每個人都有唯一的id號,我count是計算一下分組之后每組有多少的id記錄,通過這個id記錄我就知道每個組有多少人了
關於集合函數,mysql提供了以下幾種聚合函數:count、max、min、avg、sum等,上面的group_concat也算是一個聚合函數了,做字符串拼接的操作
強調:
如果我們用設置了unique約束的字段作為分組的依據,則每一條記錄自成一組,這種分組沒有意義
多條記錄之間的某個字段值相同,該字段通常用來作為分組的依據
4、 聚合函數
#強調:聚合函數聚合的是組的內容,若是沒有分組,則默認一組 示例: SELECT COUNT(*) FROM employee; #count是統計個數用的 SELECT COUNT(*) FROM employee WHERE depart_id=1; #后面跟where條件的意思是統計一下滿足depart_id=1這個的所有記錄的個數 SELECT MAX(salary) FROM employee; #max()統計分組后每組的最大值,這里沒有寫group by,那么就是統計整個表中所有記錄中薪資最大的,薪資的值 SELECT MIN(salary) FROM employee; SELECT AVG(salary) FROM employee; SELECT SUM(salary) FROM employee; SELECT SUM(salary) FROM employee WHERE depart_id=3;
5、 小練習:
1. 查詢崗位名以及崗位包含的所有員工名字
#通過上面的需求來整理邏輯:a、先看一下和哪個表有關系:所有的信息都在employee這個表里面,所以先寫from employee,找到表了
# b、看有沒有什么過濾條件,大於小於啊什么的,沒有吧,所以是不是不需要寫where條件啊
# c、看看有沒有分組的內容,也就是看看上面的需求里面有沒有分類的概念,發現是不是有啊,按照崗位來分組,對不對,所以該寫什么了:from employee group by post;
# d、然后再看需要查什么字段出來,發現是不是要看崗位名和所有員工的名字啊,所以怎么寫:select post,group_concat(name) from employee group by post;這就是完整語句了,不信你試試
下面的題都按照上面這個邏輯來搞一搞:
2. 查詢崗位名以及各崗位內包含的員工個數 3. 查詢公司內男員工和女員工的個數 4. 查詢崗位名以及各崗位的平均薪資 5. 查詢崗位名以及各崗位的最高薪資 6. 查詢崗位名以及各崗位的最低薪資 7. 查詢男員工與男員工的平均薪資,女員工與女員工的平均薪資。 #這道題我們自己提煉一下分組依據,是不是就是性別啊
#總結:先from打開文件,然后按照where后面的條件,將硬盤的數據讀到內存,內存中的到一張虛擬表,然后按照虛擬表來進行group by分組。group by 必須寫在where條件之后,寫在where之前會報錯,語法規定的
#我們說聚合函數是跟着分組來的,你看這樣一句話:select max(salary) from employee;直接也是可以使用聚合函數的,因為沒有where,那么默認是表中所有的數據,沒有group by,默認整個表是一組
8.統計各部門年齡在30歲及以上的員工平均薪資
#想一下怎么寫,1、from 表 2、where age>=30得到一張虛擬表 3、對虛擬表按部門group by 4、select 部門和聚合函數avg
#答案:select post,avg(salary) from employee where age>=30 group by post;
#看結果:
mysql> select post,avg(salary) from employee where age>=30 group by post;#因為有的部門里面的員工沒有大於30歲的,所以沒有顯示出所有的部門
+---------+---------------+
| post | avg(salary) |
+---------+---------------+
| sale | 2500.240000 |
| teacher | 255450.077500 |
+---------+---------------+
2 rows in set (0.09 sec)
到這里我們的group by就講完了,看一下我們完整查詢語句里面還有什么
SELECT distinct 字段1,字段2... FROM 庫名.表名
WHERE 條件 GROUP BY field(字段) HAVING 篩選 #過濾,過濾之后執行select后面的字段篩選,就是說我要確定一下需要哪個字段的數據,你查詢的字段數據進行去重,然后在進行下面的操作 ORDER BY field(字段) #將結果按照后面的字段進行排序 LIMIT 限制條數
注意:雖然語法里面我們先寫的select,但是並不是先執行的select,按照mysql自己的規范來執行的下面關鍵字的優先級
from where group by having select distinct order by limit

#題1:分組 mysql> select post,group_concat(name) from employee group by post; +-----------------------------------------+---------------------------------------------------------+ | post | group_concat(name) | +-----------------------------------------+---------------------------------------------------------+ | operation | 張野,程咬金,程咬銀,程咬銅,程咬鐵 | | sale | 歪歪,丫丫,丁丁,星星,格格 | | teacher | alex,wupeiqi,yuanhao,liwenzhou,jingliyang,jinxin,成龍 | | 老男孩駐沙河辦事處外交大使 | egon | +-----------------------------------------+---------------------------------------------------------+ #題目2: mysql> select post,count(id) from employee group by post; +-----------------------------------------+-----------+ | post | count(id) | +-----------------------------------------+-----------+ | operation | 5 | | sale | 5 | | teacher | 7 | | 老男孩駐沙河辦事處外交大使 | 1 | +-----------------------------------------+-----------+ #題目3: mysql> select sex,count(id) from employee group by sex; +--------+-----------+ | sex | count(id) | +--------+-----------+ | male | 10 | | female | 8 | +--------+-----------+ #題目4: mysql> select post,avg(salary) from employee group by post; +-----------------------------------------+---------------+ | post | avg(salary) | +-----------------------------------------+---------------+ | operation | 16800.026000 | | sale | 2600.294000 | | teacher | 151842.901429 | | 老男孩駐沙河辦事處外交大使 | 7300.330000 | +-----------------------------------------+---------------+ #題目5 mysql> select post,max(salary) from employee group by post; +-----------------------------------------+-------------+ | post | max(salary) | +-----------------------------------------+-------------+ | operation | 20000.00 | | sale | 4000.33 | | teacher | 1000000.31 | | 老男孩駐沙河辦事處外交大使 | 7300.33 | +-----------------------------------------+-------------+ #題目6 mysql> select post,min(salary) from employee group by post; +-----------------------------------------+-------------+ | post | min(salary) | +-----------------------------------------+-------------+ | operation | 10000.13 | | sale | 1000.37 | | teacher | 2100.00 | | 老男孩駐沙河辦事處外交大使 | 7300.33 | +-----------------------------------------+-------------+ #題目七 mysql> select sex,avg(salary) from employee group by sex; +--------+---------------+ | sex | avg(salary) | +--------+---------------+ | male | 110920.077000 | | female | 7250.183750 | +--------+---------------+
六 HAVING過濾
講having之前,我們補充一個點:之前我們寫的查詢語句是這樣的:select id,name from employee;實際上我們在select每個字段的時候,省略了一個表名,有的人可能會這樣寫,select employee.id,employee.name from employee;你會發現查詢出來的結果是一樣的,但是如果你要將查詢出來的結果表,起一個新表名的話,帶着表名這樣寫就錯了
select employee.id,employee.name from employee as tb1;這樣執行會下面的報錯:
mysql> select employee.id,employee.name from employee as tb1;
ERROR 1054 (42S22): Unknown column 'employee.id' in 'field list'
因為這個語句先執行的是誰啊,是不是我們的from啊,那么后面的as也是比select要先執行的,所以你先將表employee起了個新名字叫做tb1,然后在tb1里面取查詢數據,那么tb1里面找不到employee.id這個字段,就會報錯,如果我們查詢的時候不帶表名,你as來起一個新的表名也是沒問題的,簡單提一下這個內容,知道就好了
HAVING與WHERE不一樣的地方在於!!!!!!
having的語法格式和where是一模一樣的,只不過having是在分組之后進行的進一步的過濾,where不能使用聚合函數,having是可以使用聚合函數的
#!!!執行優先級從高到低:where > group by > having #1. Where 發生在分組group by之前,因而Where中可以有任意字段,但是絕對不能使用聚合函數。 #2. Having發生在分組group by之后,因而Having中可以使用分組的字段,無法直接取到其他字段,having是可以使用聚合函數
having簡單測試:
#來個需求:統計各部門年齡在30歲及以上的員工的平均薪資,並且保留平均工資大於10000的部門
答案:select post,avg(salary) as new_sa from employee where age>=30 group by post having avg(salary) > 10000;
看結果:
+---------+---------------+
| post | new_sa |
+---------+---------------+
| teacher | 255450.077500 |
+---------+---------------+
1 row in set (0.00 sec)
然后我們看這樣一句話:select * from employee having avg(salary) > 10000;
只要一運行就會報錯:
mysql> select * from employee having avg(salary) > 10000;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
是因為having只能在group by后面運行
小練習:
1. 查詢各崗位內包含的員工個數小於2的崗位名、崗位內包含員工名字、個數 3. 查詢各崗位平均薪資大於10000的崗位名、平均工資 4. 查詢各崗位平均薪資大於10000且小於20000的崗位名、平均工資

#題1: mysql> select post,group_concat(name),count(id) from employee group by post having count(id) < 2; +-----------------------------------------+--------------------+-----------+ | post | group_concat(name) | count(id) | +-----------------------------------------+--------------------+-----------+ | 老男孩駐沙河辦事處外交大使 | egon | 1 | +-----------------------------------------+--------------------+-----------+ #題目2: mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | operation | 16800.026000 | | teacher | 151842.901429 | +-----------+---------------+ #題目3: mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) <20000; +-----------+--------------+ | post | avg(salary) | +-----------+--------------+ | operation | 16800.026000 | +-----------+--------------+
說一下去重:distinct
將查詢的結果進行去重:select distinct post from employee; 注意distinct去重要寫在查詢字段的前面,不然會報錯,關於distinct使用時的其他問題看下面的總結

有時需要查詢出某個字段不重復的記錄,這時可以使用mysql提供的distinct這個關鍵字來過濾重復的記錄,但是實際中我們往往用distinct來返回不重復字段的條數(count(distinct id)),其原因是distinct只能返回他的目標字段,而無法返回其他字段,distinct 想寫在其他字段后面需要配合聚合函數來寫。 mysql> select id,count(distinct post) from employee; ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause 報錯了:是因為distinct不能返回其他的字段,只能返回目標字段 mysql> select count(distinct post) from employee; +----------------------+ | count(distinct post) | +----------------------+ | 4 | +----------------------+ 1 row in set (0.00 sec)
說完去重,我們看一下order by,排序
七 查詢排序:ORDER BY
按單列排序 SELECT * FROM employee ORDER BY salary; #默認是升序排列 SELECT * FROM employee ORDER BY salary ASC; #升序 SELECT * FROM employee ORDER BY salary DESC; #降序 但是你看,如果我們按照age來排序,你看看是什么效果: mysql> SELECT * FROM employee ORDER BY age; +----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 | | 17 | 程咬銅 | male | 18 | 2015-04-11 | operation | NULL | 18000.00 | 403 | 3 | | 16 | 程咬銀 | female | 18 | 2013-03-11 | operation | NULL | 19000.00 | 403 | 3 | | 15 | 程咬金 | male | 18 | 1997-03-12 | operation | NULL | 20000.00 | 403 | 3 | | 12 | 星星 | female | 18 | 2016-05-13 | sale | NULL | 3000.29 | 402 | 2 | | 11 | 丁丁 | female | 18 | 2011-03-12 | sale | NULL | 1000.37 | 402 | 2 | | 18 | 程咬鐵 | female | 18 | 2014-05-12 | operation | NULL | 17000.00 | 403 | 3 | | 7 | jinxin | male | 18 | 1900-03-01 | teacher | NULL | 30000.00 | 401 | 1 | | 6 | jingliyang | female | 18 | 2011-02-11 | teacher | NULL | 9000.00 | 401 | 1 | | 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 | | 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | | 5 | liwenzhou | male | 28 | 2012-11-01 | teacher | NULL | 2100.00 | 401 | 1 | | 10 | 丫丫 | female | 38 | 2010-11-01 | sale | NULL | 2000.35 | 402 | 2 | | 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 | | 8 | 成龍 | male | 48 | 2010-11-11 | teacher | NULL | 10000.00 | 401 | 1 | | 4 | yuanhao | male | 73 | 2014-07-01 | teacher | NULL | 3500.00 | 401 | 1 | | 2 | alex | male | 78 | 2015-03-02 | teacher | NULL | 1000000.31 | 401 | 1 | | 3 | wupeiqi | male | 81 | 2013-03-05 | teacher | NULL | 8300.00 | 401 | 1 | +----+------------+--------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ 發現什么,按照年齡來升序排的,沒問題,但是你看年齡相同的那些按什么排的,是不是看着是亂的啊,但是不管它對這種相同數據的內容怎么排序,我們是不是想如果出現相同的數據,那么這些相同的數據也按照一個依據來排列啊: 所以我們可以給相同的這些數據指定一個排序的依據,看下面: 按多列排序:先按照age升序,如果年紀相同,則按照薪資降序 SELECT * from employee ORDER BY age, #注意排序的條件用逗號分隔 salary DESC;
小練習:
1. 查詢所有員工信息,先按照age升序排序,如果age相同則按照hire_date降序排序 2. 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資升序排列 3. 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資降序排列
#題目1 mysql> select * from employee ORDER BY age asc,hire_date desc; #題目2 mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) asc; #注意:查詢語句的語法是固定上面這樣寫的,但是運行順序是這樣的:1、from 2、where 3、group by 4、having 5、select 6、distinct 7、order by 8、limit,我們下面要學的 +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | operation | 16800.026000 | | teacher | 151842.901429 | +-----------+---------------+ #題目3 mysql> select post,avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) desc; +-----------+---------------+ | post | avg(salary) | +-----------+---------------+ | teacher | 151842.901429 | | operation | 16800.026000 | +-----------+---------------+
八 限制查詢的記錄數:LIMIT
示例:
#取出工資最高的前三位 SELECT * FROM employee ORDER BY salary DESC LIMIT 3; #默認初始位置為0,從第一條開始順序取出三條 SELECT * FROM employee ORDER BY salary DESC LIMIT 0,5; #從第0開始,即先查詢出第一條,然后包含這一條在內往后查5條 SELECT * FROM employee ORDER BY salary DESC LIMIT 5,5; #從第5開始,即先查詢出第6條,然后包含這一條在內往后查5條
小練習:分頁顯示,每頁顯示5條。我們工作中經常會涉及到數據分頁顯示,因為數據量很大的時候,加入上10w條數據,我們是不是要分開給用戶顯示啊,要不然頁面上都顯示不過來,即便是顯示過來了,用戶看着是不是也很不爽啊,要一直往下面滾輪,對不對,用戶體驗不好,所以你會發現有好多的網站都可以看到一個分頁的功能。
mysql> select * from employee limit 0,5; +----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ | 1 | egon | male | 18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL | 7300.33 | 401 | 1 | | 2 | alex | male | 78 | 2015-03-02 | teacher | | 1000000.31 | 401 | 1 | | 3 | wupeiqi | male | 81 | 2013-03-05 | teacher | NULL | 8300.00 | 401 | 1 | | 4 | yuanhao | male | 73 | 2014-07-01 | teacher | NULL | 3500.00 | 401 | 1 | | 5 | liwenzhou | male | 28 | 2012-11-01 | teacher | NULL | 2100.00 | 401 | 1 | +----+-----------+------+-----+------------+-----------------------------------------+--------------+------------+--------+-----------+ 5 rows in set (0.00 sec) mysql> select * from employee limit 5,5; +----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+ | 6 | jingliyang | female | 18 | 2011-02-11 | teacher | NULL | 9000.00 | 401 | 1 | | 7 | jinxin | male | 18 | 1900-03-01 | teacher | NULL | 30000.00 | 401 | 1 | | 8 | 成龍 | male | 48 | 2010-11-11 | teacher | NULL | 10000.00 | 401 | 1 | | 9 | 歪歪 | female | 48 | 2015-03-11 | sale | NULL | 3000.13 | 402 | 2 | | 10 | 丫丫 | female | 38 | 2010-11-01 | sale | NULL | 2000.35 | 402 | 2 | +----+------------+--------+-----+------------+---------+--------------+----------+--------+-----------+ 5 rows in set (0.00 sec) mysql> select * from employee limit 10,5; +----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+ | id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | +----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+ | 11 | 丁丁 | female | 18 | 2011-03-12 | sale | NULL | 1000.37 | 402 | 2 | | 12 | 星星 | female | 18 | 2016-05-13 | sale | NULL | 3000.29 | 402 | 2 | | 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 | | 14 | 張野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | | 15 | 程咬金 | male | 18 | 1997-03-12 | operation | NULL | 20000.00 | 403 | 3 | +----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+ 5 rows in set (0.00 sec)
到最后不夠五條了怎么辦,完全不影響,接着寫
mysql> select * from employee limit 15,5;
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
| 16 | 程咬銀 | female | 18 | 2013-03-11 | operation | NULL | 19000.00 | 403 | 3 |
| 17 | 程咬銅 | male | 18 | 2015-04-11 | operation | NULL | 18000.00 | 403 | 3 |
| 18 | 程咬鐵 | female | 18 | 2014-05-12 | operation | NULL | 17000.00 | 403 | 3 |
+----+-----------+--------+-----+------------+-----------+--------------+----------+--------+-----------+
3 rows in set (0.00 sec)
#到目前為止,單表查詢所有的語法都講完了,語法就是按照我們博客最上面說的語法順序來寫,但是執行的時候,要按照對應的各個方法的優先級去執行。
九 使用正則表達式查詢
#之前我們用like做模糊匹配,只有%和_,局限性比較強,所以我們說一個正則,之前我們是不是學過正則匹配,你之前學的正則表達式都可以用,正則是通用的
SELECT * FROM employee WHERE name REGEXP '^ale'; SELECT * FROM employee WHERE name REGEXP 'on$'; SELECT * FROM employee WHERE name REGEXP 'm{2}'; 小結:對字符串匹配的方式 WHERE name = 'egon'; WHERE name LIKE 'yua%'; WHERE name REGEXP 'on$';
小練習:
查看所有員工中名字是jin開頭,n或者g結果的員工信息
select * from employee where name regexp '^jin.*[g|n]$';