一、單表查詢
單表查詢的完整語法:
1、完整語法(語法級別關鍵字的排列順序如下) select distinct 字段1,字段2,字段3,... from 庫名.表名 where 約束條件 group by 分組依據 having 過濾條件 order by 排序的字段 limit 限制顯示的條數 ;
必須要有的關鍵字如下:
select * from t1; 分析之前先將其進行占位,需要什么在進行添加
關鍵字執行的優先級:
from
where
group by
having
distinct
order by
limit
上面的關鍵字的執行的優先級可以用偽代碼的形式寫出來:
運行級別:
def from(dir,file): open('%s\%s' %(dir,file),'r') return f def where(f,pattern): for line in f: if pattern: yield line def group(): pass def having(): pass def distinct(): pass def order(): pass def limit(): pass def select(): f=from() res1=where(f) res2=group(res1) res3=having(res2) res4=distinct(res3) res5=order(res4) limit(res5)
事先創建好表和插入記錄

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
1、簡單查詢
select * from t1; #查詢t1表中所有字段的記錄內容 select id,name,sex from t1; #查詢指定字段的記錄內容 select distinct post from emp; #查詢emp表中post字段,並為其去重
通過四則運算進行查詢:
select name,salary*12 as annual_salary from emp; #查詢表中的指定字段做四則運算,並通過as為字段起別
避免重復DISTINCT
SELECT DISTINCT post FROM employee; #為某一個字段去重
定義顯示格式:
CONCAT() 函數用於連接字符串 select concat('名字: ',name) as new_name,concat("年齡: ",age) as new_age from emp; #concat在指定的字段記錄內容前拼接上我們要的格式,並重新為指定字段起別名 select concat(name,":",age) from emp; #將兩個字段的記錄內容通過分隔符拼接成一個字段記錄內容 select concat(name,":",age,":",sex) from emp; #也可以將多個字段記錄通過多個分隔符拼接成一個字段記錄內容 CONCAT_WS() 第一個參數為分隔符--------------會在每一個字段主鍵加上冒號 select concat_ws(":",name,age,sex) as info from emp;#每個字段記錄內容之間都要用分隔符是不是覺得很麻煩,那么讓我們用concat_ws通過一個分隔符就可以搞定上面相同的效果了 case:可以跟多個條件,當然這種篩選完全可以在程序中實現 SELECT ( CASE WHEN NAME = 'egon' THEN NAME #名字是egon的直接打印出他打的名字 WHEN NAME = 'alex' THEN #名字是alex的,做一個拼接操作 CONCAT(name,'_BIGSB') ELSE concat(NAME, 'SB') #其余的名字也做一個名字的拼接操作 END ) as new_name FROM emp;
二、where:是分組前的過濾條件,不能直接使用聚合函數
where字句中可以使用:
1. 比較運算符:> < >= <= <> !=
2. between 80 and 100 值在10到20之間
3. in(80,90,100) 值是10或20或30
4. like 'egon%'
pattern可以是%或_,
%表示任意多字符
_表示一個字符
5. 邏輯運算符:在多個條件直接可以使用邏輯運算符 and or not
從硬盤讀到內存,沒將優化機制就要每一條記錄都要進行讀取到內存,這樣隨着記錄條數的增加,會拖慢查詢的速度
select * from emp where id >= 10 and id <=15; # 等同於select * from emp where id between 10 and 15; #10<=id<=15 select * from emp where id = 6 or id = 9 or id = 12; # 等同於select * from emp where id in (6,9,12); #_代表任意單個字符 #%代表任意無窮個字符 select * from emp where name like "__"; #模糊匹配篩選出只包含兩個任意字符的名字 select * from emp where name like "jin%"; #模糊匹配篩選出名字是以jin開頭的所有名字(jin后面可以跟任意多個字符) select * from emp where id not in (6,9,12); #篩選出id不是in括號內的所有記錄內容 select * from emp where id not between 10 and 15;#篩選出id不是10<=id<=15的所有字段的記錄內容 #要求:查詢員工姓名中包含i字母的員工姓名與其薪資 select name,salary from db39.emp where name like '%i%' #要求:查詢員工姓名是由四個字符組成的的員工姓名與其薪資 select name,salary from db39.emp where name like '____'; #_任意單個字符,%任意無窮個字符 select name,salary from db39.emp where char_length(name) = 4; select * from db39.emp where id not between 3 and 6; select * from emp where salary not in (20000,18000,17000); #要求:查詢崗位描述為空的員工名與崗位名 select name,post from db39.emp where post_comment is NULL; select name,post from db39.emp where post_comment is not NULL;
三、group by分組
1、什么分組:按照所有記錄相同的部分進行歸類,一定區分度低的字段
2、為何要分組:當我們要以組為單位進行統計時就必須分組,分組的目的是為了以組為單位進行統計的,再去考慮單條記錄毫無意義
3、設置sql_mode為only_full_group_by,意味着以后但凡分組,只能取到分組的依據
mysql> set global sql_mode="strict_trans_tables,only_full_group_by";
分組之后只能查到分組的字段,以及組內多條記錄聚合的成果,要*也不會報錯,只會給出每一組的第一條記錄
set global sql_mode="strict_trans_tables,only_full_group_by"; #將mysql設置為嚴格模式
注意:分組之后,只能查到分組的字段以及組內多條記錄聚合的成果---------------分組之前where不能直接使用聚合函數
select * from emp group by post; #對post進行分組,然后查看所有字段的記錄,但是這種單純的查看是沒有意義的 因為分組后查詢的結果只是分組后每組的第一條記錄 # 聚合函數------------------------結合分組進行使用 max min avg sum count select post,count(id) from emp group by post; #按post字段進行分組,並統計每個分組的記錄個數,一般是id作為統計每個分組記錄的個數,當然你想用其他的字段也是可以的 select post,max(salary) from emp group by post; #按post字段進行分組,並統計每組最高薪水的記錄,當然為了好看,你還可以給字段起別名 select post,avg(salary) from emp group by post; #按post字段進行分組,並統計每組最底薪水的記錄 select sex,count(sex) from emp group by sex; #按post字段進行分組,count可以寫表中存在的任意字段,並不影響最終查詢的結果 # 統計出每個部門年齡30以上的員工的平均薪資 select post,avg(salary) from emp where age >= 30 group by post; #按照post字段進行分組,篩選出年齡大於30的平均薪資,當然你還可以給平均薪資起別名 # 注意:分組是在where之后發生的 mysql> select * from emp where max(salary) > 3000; #分組之前where不能直接使用聚合函數 ERROR 1111 (HY000): Invalid use of group function select max(salary) from emp where salary > 3000; #通過where篩選條件在使用聚合函數是沒有問題的 # group_concat select post,group_concat(name,':',age) from emp group by post; #將分組后的多個字段多一個拼接操作,當然我們依然可以為新字段起別名
四、having 過濾條件----having在分組之后,可以直接使用聚合函數
where是在分組之前的過濾,即在分組之前做了一次整體性的篩選
having是在分組之后的過濾,即在分組之后專門針對聚合的結果進行進一步的篩選
新增字段均可以為其起別名
select post,avg(salary) from emp group by post having avg(salary) > 10000; #按post進行分組,並按having后的篩選條進行篩選,然后求出平均值 select post,avg(salary) from emp group by post ; #只是單純的求每個部門的平均薪資,並沒有為其添加篩選條件
五、order by排序
select * from emp order by age asc; # 默認asc升序-》從小到大---------ascend上升 select * from emp order by age desc;# desc降序-》從大到小------------descend下降 select * from emp order by age asc,salary desc; # 先按照age升序排列,如果age相同則按照salary降序排 select post,avg(salary) from emp group by post order by avg(salary); #沒有寫是按照升序還是降序的順序進行排序,默認的是按照升序進行排序的
六、limit 限制顯示的條件
select * from emp limit 3; #查看表中的記錄條數,可以設置我們想要的顯示條數,我們還可以指點顯示條數的起點,以及顯示幾條 #薪資最高那個人的詳細信息 select * from emp order by salary desc limit 1; #按照薪資降序得到一張新表,新表的第一條記錄即我們想要的結果 # 分頁顯示 select * from emp limit 0,5; # 從0開始往后取5條 select * from emp limit 5,5; #從5開始往后取5條
正則表達式
select * from emp where name regexp "^jin.*(g|n)$"; #模糊匹配太過有限,這時我們強大的正則就派上用場了
七、多表查詢
事先創建好表和插入記錄

#建表 create table department( id int, name varchar(20) ); create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int ); #插入數據 insert into department values (200,'技術'), (201,'人力資源'), (202,'銷售'), (203,'運營'); insert into employee(name,sex,age,dep_id) values ('egon','male',18,200), ('alex','female',48,201), ('wupeiqi','male',38,201), ('yuanhao','female',28,202), ('liwenzhou','male',18,200), ('jingliyang','female',18,204) ; #查看表結構和數據 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ mysql> desc employee; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+ mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技術 | | 201 | 人力資源 | | 202 | 銷售 | | 203 | 運營 | +------+--------------+ mysql> select * from employee; +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+
1、內連接:把兩張表有對應關系的記錄連接成一張虛擬表,在笛卡爾積基礎上做了篩選---inner join
1、內連接:把兩張表有對應關系的記錄連接成一張虛擬表-----在笛卡爾積基礎上做了一個篩選 會將左右兩張表沒有對應關系的也篩選掉 select * from emp inner join dep on emp.dep_id = dep.id; #on條件篩選出我們需要符合條件的記錄,我們可以添加where進一步根據需求進行篩選 左表 右表 連表的條件 #應用: 笛卡爾積 將左表中的每一條記錄與右表中的所有條記錄進行匹配 select * from emp,dep where emp.dep_id = dep.id and dep.name = "技術"; # 不要用where做連表的活 select * from emp inner join dep on emp.dep_id = dep.id #on做的是將兩張表連接成一張表的篩選條件 where dep.name = "技術"; #where做連接成一張表后的篩選條件
2、左連接:在內連接的基礎上,保留左邊沒有對應關系的記錄-----left join
select * from emp left join dep on emp.dep_id = dep.id;
3、右連接:在內連接的基礎上,保留右邊沒有對應關系的記錄-----right join
select * from emp right join dep on emp.dep_id = dep.id;
4、全連接:在內連接的基礎上,保留左、右邊沒有對應關系的記錄---左連接 union 右連接
select * from emp left join dep on emp.dep_id = dep.id union select * from emp right join dep on emp.dep_id = dep.id;
多表查詢思路:先定位到和那些表有關,合成一張大表,在基於一張大表進行查詢(單表查詢)
應用:
#補充:多表連接可以不斷地與虛擬表連接 #查找各部門最高工資 select t1.* from emp as t1 inner join (select post,max(salary) as ms from emp group by post) as t2 #拿到每個部門最高的工資 on t1.post = t2.post where t1.salary = t2.ms ;
八、子查詢
子查詢:就是一個查詢語句的查詢結果用括號括起來當做另外一個查詢語句的條件取用
#1:子查詢是將一個查詢語句嵌套在另一個查詢語句中。 #2:內層查詢語句的查詢結果,可以為外層查詢語句提供查詢條件。 #3:子查詢中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字 #4:還可以包含比較運算符:= 、 !=、> 、<等
1、帶IN關鍵字的子查詢
#查詢平均年齡在25歲以上的部門名 select id,name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25); #查看技術部員工姓名 select name from employee where dep_id in (select id from department where name='技術'); #查看不足1人的部門名(子查詢得到的是有人的部門id)select name from department where id not in (select distinct dep_id from employee);
2、 帶比較運算符的子查詢
#比較運算符:=、!=、>、>=、<、<=、<> #查詢大於所有人平均年齡的員工名與年齡 mysql> select name,age from emp where age > (select avg(age) from emp); +---------+------+ | name | age | +---------+------+ | alex | 48 | | wupeiqi | 38 | +---------+------+ rows in set (0.00 sec) #查詢大於部門內平均年齡的員工名、年齡 select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
3、 帶EXISTS關鍵字的子查詢
EXISTS關字鍵字表示存在。在使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄。
而是返回一個真假值。True或False
當返回True時,外層查詢語句將進行查詢;當返回值為False時,外層查詢語句不進行查詢
#department表中存在dept_id=203,Ture mysql> select * from employee -> where exists -> (select id from department where id=200); +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+ #department表中存在dept_id=205,False mysql> select * from employee -> where exists -> (select id from department where id=204); Empty set (0.00 sec)