一、表的基本查詢語句及方法
from、 where、 group by(分組)、having(分組后的篩選)、distinct(去重)、order by(排序)、 limit(限制)
1、單表查詢:
先創建表,數據量稍微多點的表
create table emp( id int not null unique auto_increment, # 和設主建同理 forgeing key name varchar(20) not null, sex enum('male','femlae') not null default 'male' # 默認值大部分都是男的 age int(3) unsigned not null default 28, hire_date date not null, post varcher(50), post_comment varcher(100), salary double(15,2), office int,# 一個部門一個屋子 depart_id int ); #插入記錄 #三個部門:教學,銷售,運營 insert into emp(name,sex,age,hire_date,post,salary,office,depart_id) values ('jason','male',18,'20170301','張江第一帥形象代言',7300.33,401,1), #以下是教學部 ('egon','male',78,'20150302','teacher',1000000.31,401,1), ('kevin','male',81,'20130305','teacher',8300,401,1), ('tank','male',73,'20140701','teacher',3500,401,1), ('owen','male',28,'20121101','teacher',2100,401,1), ('jerry','female',18,'20110211','teacher',9000,401,1), ('nick','male',18,'19000301','teacher',30000,401,1), ('sean','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 from emp where id >= 3 and id <= 6;
1、語法的書寫順序
select 、from、where、group by
2、執行的順序
from、where、group by、select
3、where約束條件
(1)1.查詢id大於等於3小於等於6的數據
select id,name from emp where id>=3 and is<=6; select *from emp where id between 3 and 6; # 等價於第一句寫法
(2).查詢薪資是20000或者18000或者17000的數據
select *from emp where salary =20000 or salary = 18000 or 17000; select *from emp where salary in (20000,18000,17000); # 等價 簡寫
(3).查詢員工姓名中包含o字母的員工姓名和薪資
模糊匹配:
like: %匹配多個任意字符、_:匹配任意字符
對於較復雜的條件在書寫MySQL語句的時候,先按查詢的優先級順序拼寫出來,如先where條件 在確定分組的數據里篩選
""" 先是查哪張表 from emp 再是根據什么條件去查 where name like ‘%o%’ 再是對查詢出來的數據篩選展示部分 select name,salary """ select name,salary from emp where name like '%o%';
(4)查詢員工姓名是由四個字符組成的員工姓名與其薪資
select name,salary from emp where name like '____' # 四個空格匹配任意字符 select naem,salary from enp where char_lenhth(name)=4;
(5) 查詢id小於3或者大於6的數據
select *from emp where id not between 3 and 6; select *from emp where id<3 and id<6; # 兩種寫法
6.查詢薪資不在20000,18000,17000范圍的數據
select *from emp where salary not in (2000,17000,18000); # 取反操作
(7).查詢崗位描述為空的員工名與崗位名 對null不能用等號,只能用is
4、group by (分組)
數據分組應用場景:每個部門的平均薪資,男女比例等
(1)、按部門分組
如果你的MySQL不報錯 說明嚴格模式沒有設置,需要添加修改設置
# 設置嚴格模式 show variables like '%mode'; set session sql_mode # 當前窗口有效 set global # 全局有效 set global sql_mode ="strict_trans_tables,only_full_group_by"; # 設置后重新連接服務端
分組語法:
select *from emp group by post; 屬於錯誤的寫法,應該按照嚴格的分組后的匹配的數據 #在沒有設置嚴格模式的情況下,會默認按部門的分組取出部門的第一個人的信息
分組之后應該做到最小單位是組,而不應該再展示組內的單個數據信息
MySQL中分組后,只拿到分組的字段信息,無法直接獲取其他字段信息,可以通過其他方法(聚合函數)簡單獲取;
設置sql_mode為only_full_group_by,意味着以后但凡分組,只能取到分組的依據, 不應該在去取組里面的單個元素的值,那樣的話分組就沒有意義了,因為不分組就是對單個元素信息的隨意獲取 """ set global sql_mode="strict_trans_tables,only_full_group_by"; # 重新鏈接客戶端 select * from emp group by post; # 報錯 select id,name,sex from emp group by post; # 報錯 select post from emp group by post; # 獲取部門信息 # 強調:只要分組了,就不能夠再“直接”查找到單個數據信息了,只能獲取到組名
設置開啟嚴格模式:
聚合函數: max min avg sum connt 一般不會單獨出現都是有分組出現時才會用到
(2)、分組后用聚合函數的方法
# 以組為單位統計組內的數據>>聚合到一起(聚集到一起合成為一個結果) # 每個部門的最高工資 select post,max(salary) from emp group by post; # 每個部門的最低工資 select post,min(salary) from emp group by post: # 每個部門的平均工資 select post,avg(salary) from emp group by post; # 每個部門的人數 select post,count(id) from emp group by post;
# 在統計分組內個數的時候 填寫任意非空字段都可以完成計數,推薦使用能夠唯一標識數據的字段
比如id字段
3.查詢分組之后的部門名稱和每個部門下所有的學生姓名
# group_concat(分組之后用)不僅可以用來顯示除分組外字段還有拼接字符串的作用
select post,group_cocat(name) from emp group by post; select post,group_concat(name,_'sb") from emp group by post; # 拼接顯示 select post,group_concat(name:'salary') from emp group by poat; select post,group_concat(salary) from emp group by post;
4、補充concat(不分組時用)拼接字符串達到更好的顯示效果 as語法使用
select name as 姓名,salary as 薪資 from emp;
select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪資 from emp;
# 補充as語法,即可以給字段起別名也可以給表名起
select emp.id,emp.name from emp as t1; # 報錯 因為表名已經被你改成了t1 select t1.id,t1.name from emp as t1; # 查詢四則運算 # 查詢每個人的年薪 select name,salary*12 as annual_salary from emp; select name,salary*12 annual_salary from emp; # as可以省略
結果:
寫復雜的sql語句的時候注意:按執行的順序從后寫到前
""" 寫sql語句的時候 一定不要一口氣寫完 前期先按照步驟一步步寫 寫一步查詢看一下結果然后基於當前結果再往后寫 """ # 把復雜的語句拆分開來寫
二、having
必須用在組合之后的語句,不能單獨使用
以上學過的語法:
select 查詢字段1,查詢字段2,....from 表名 where 過濾條件 group by 分組依據 # 語法這么寫,但是執行順序卻不一樣 from where group by select
having的語法格式與where 一致,只不過having是在分組之后進行的過濾,
即where雖然不能用聚合函數,但having可以
1、統計各部門年齡在30歲以上的員工平均工資,並且保留平均工資大於10000的部門
select post,avg(salary) from emp where age>=30 group by post having avg(salary)>100000; #強調:having必須在group by 的后i面使用,不能單獨使用 select *from emo having avg (salary)>10000; # 結果不報錯!
執行的順序: from 、where、 group by 、 having 、 select
having單獨使用會報錯:
三、distinct
將重復的數據進行一個去重的操作,去重必須數據是一模一樣的才能去重
# 對有重復的展示數據進行去重操作 select distinct post from emp;
四、order by
對標進行排序的操作,asc(默認升序排),desc(默認降序排) 如果不寫會默認是升序排列
select *from emp order by salary asc; # 默認為升序排列 select *from emp order by salary desc: # 默認為降序排 # 先按照age 降序排,在年薪相同的情況下再按照薪資升序排 select *from emp order by age desc,salary asc; # 統計各部門年齡在10歲以上的員工平均工資,並且保留平均工資大於1000的部門,然后對平均工資進行排序; select post,avg(salary) from emp where age>10 group by post having avg(salary)>100 order by avg(salary)
五、limit
限制展示條數
select *from emp limit 5; # 查詢工資最高的人的詳細信息 select *from emp order by salary desc limit 1; # 先降序排列 然后限制一條數據即可 # 分頁顯示 select *from emp limit 0,5; # 第一個參數表示的是起始位置,第二個表示的是顯示的條數 select *from emp limit 6,10; # 表示的是從第六個開始,顯示10個數據
六、正則
在編程中 只要看到reg開頭的 基本上都是跟正則相關
select * from emp where name regexp '^j.*(n|y)$'; # 匹配以‘j’開頭的o個或多個以n或y 結尾的名字
七、多表查詢
表查詢分為兩大類
1.聯表查詢
2.子查詢
select * from emp,dep; # 左表一條記錄與右表所有記錄都對應一遍>>>笛卡爾積
笛卡爾乘積是指在數學中,兩個集合X和Y的笛卡尓積(Cartesian product),又稱直積,表示為X × Y,第一個對象是X的成員而第二個對象是Y的所有可能有序對的其中一個成員
建表:
#建表 create table dep( id int, name varchar(20) ); create table emp( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int ); #插入數據 insert into dep values (200,'技術'), (201,'人力資源'), (202,'銷售'), (203,'運營'); insert into emp(name,sex,age,dep_id) values ('jason','male',18,200), ('egon','female',48,201), ('kevin','male',38,201), ('nick','female',28,202), ('owen','male',18,200), ('jerry','female',18,204) ; # 當初為什么我們要分表,就是為了方便管理,在硬盤上確實是多張表,但是到了內存中我們應該把他們再拼成一張表進行查詢才合理
# 查詢員工及所在部門的信息 select * from emp,dep where emp.dep_id = dep.id; # 查詢部門為技術部的員工及部門信息 select * from emp,dep where emp.dep_id = dep.id and dep.name = '技術';
通過連表查詢能准確的查詢兩表之間的詳細信息
有專門幫你做連表的方法 內連接(inner join) 左連接(left join) 右連接(right join) 全連接(union) # 只要將左連接和右連接的sql語句 加一個union就變成全連接
方法的使用:
# 將兩張表關聯到一起的操作,有專門對應的方法 # 1、內連接:只取兩張表有對應關系的記錄 select * from emp inner join dep on emp.dep_id = dep.id; select * from emp inner join dep on emp.dep_id = dep.id where dep.name = "技術"; # 2、左連接: 在內連接的基礎上保留左表沒有對應關系的記錄 select * from emp left join dep on emp.dep_id = dep.id; # 3、右連接: 在內連接的基礎上保留右表沒有對應關系的記錄 select * from emp right join dep on emp.dep_id = dep.id; # 4、全連接:在內連接的基礎上保留左、右面表沒有對應關系的的記錄 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;
數據庫在通過連接兩張或多張表來返回記錄時,都會生成一張中間的臨時表,然后再將這張臨時表返回給用戶。 在使用left jion時,on和where條件的區別如下:
1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
2、where條件是在臨時表生成好后,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉。
左連接:
右連接:
全連接:
# 1.查詢部門是技術或者人力資源的員工信息 """ 先獲取技術部和人力資源部的id號,再去員工表里面根據前面的id篩選出符合要求的員工信息 """ select * from emp where dep_id in (select id from dep where name = "技術" or name = "人力資源"); # 2.每個部門最新入職的員工 思路:先查每個部門最新入職的員工,再按部門對應上聯表查詢 select t1.id,t1.name,t1.hire_date,t1.post,t2.* from emp as t1 # 看作t1 inner join (select post,max(hire_date) as max_date from emp group by post) as t2 on t1.post = t2.post where t1.hire_date = t2.max_date ; """ 記住一個規律,表的查詢結果可以作為其他表的查詢條件,也可以通過其別名的方式把它作為一張虛擬表去跟其他表做關聯查詢 """ select * from emp inner join dep on emp.dep_id = dep.id;