表查询语句及使用-连表(inner join-left join)-子查询

一、表的基本查询语句及方法

    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;  # 左表一条记录与右表所有记录都对应一遍>>>笛卡尔积

  笛卡尔乘积是指在数学中,两个集合XY的笛卡尓积(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;

 

  

  

  

  

  

  

原文地址:https://www.cnblogs.com/Gaimo/p/11390009.html