前言

昨天学习了表与表之间的关系、多表关联、复制表、单表查询的知识,今天学习的内容是单表查询与关键词的执行顺序、正则表达式以及最重要的多表查询。

数据库增删改

insert [into] 表名[(可选字段名)] values(一组值1),(一组值2),...;

into 可以省略,表名后的字段可选,如果写了后面的 values 中的值必须与表名后的字段意义对应,如果没写后面的 values 中的值必须与表的所有字段一一对应,values后面可以给出多组值并用逗号隔开。

delete from 表名[where 条件]; 

如果条件不写的话是删除所有记录,不过这样删除表的效率很低,因为是一行行删除数据,自增的 id不会归零。使用truncate 是重建表,先记录表结构然后删除整个表再重新建表出来,自增的 id 会归零。

update 表名 set 字段名 = 值,[,字段2 = 值2],[where 条件];

可以一次性修改多个字段的值,值之间需要用逗号隔开;如果不写条件的话就是修改所有记录。

单表查询

不带关键字的查询

select (*|字段名|四则运算|聚合函数) from 表名 [where 条件]; 

准备数据

mysql> create table stu(id int primary key auto_increment,
       name char(10),
       math int,
       english int);
mysql> insert into stu values(null,'赵云',90,30);
mysql> insert into stu values(null,'小乔',90,60);
mysql> insert into stu values(null,'小乔',90.60);
mysql> insert into stu values(null,'大乔',10,70);
mysql> insert into stu values(null,'李清照',100,100);
mysql> insert into stu values(null,'铁拐李',20,55);
mysql> insert into stu values(null,'小李子',20,55);

*** 表示查询所有字段**

mysql> select * from stu;

字段名 可以手动指定要查询的字段

mysql> select engish from stu;

字段的值可以进行加减乘除

统计总分

mysql> select math+ english from stu;

如果觉得 math+english 名字太长也可以取别名

mysql> select math+english [as] 总分 from stu; 

as可以省略

给英语成绩加分

mysql> select english+10 from stu;

聚合函数 用于统计

什么是聚合函数,将多个数据进行计算,并得到一个结果,称为聚合

聚合函数:

注意不能再 where 后面使用聚合函数,因为 where 相当于打开文件然后读取文件中的数据,而使用聚合函数很显然需要多个值来聚合,那么没有读取完数据就使用不了聚合函数,所以这时候应该使用 on,所以聚合函数不能写在 where 后面,where会最先执行,它的作用是读取数据并过滤

  • sum
mysql> select sum(salary) from emp;

  • count
mysql> select count(*) from emp group by dept;

  • avg
mysql> select avg(salary) from emp;

  • max/min
mysql> select max(salary) from emp;
mysql> select min(salary) from emp;

结合使用:

mysql> select dept,count(name) from emp group by dept;

where 是可选的

关键字的执行顺序

from

用于打开文件

distinct

去除重复数据,所有数据全都重复才算重复

mysql> select distinct * from stu;

where

对读取的数据进行过滤

where 后面跟的条件比较多:

between and

mysql> select * from stu where english between 70 and 80;

in

mysql> select * from stu where math in (89,90,91);

like

mysql> select * from stu where name like '李%';

and

mysql> select * from stu where math > 80 and english > 80;

mysql> select * from stu where math > 60 and english < 60;

group by

对数据进行分组,为了进行统计。group by 后面可以有多个分组依据,会按照顺序执行

准备数据

mysql> create table emp(
       id int,
       name char(10),
       sex char,
       dept char(10),
       job char(10),
       salary double);
mysql> insert into emp values(
       (1,'刘备','男','市场','总监',5800),
       (2,'张飞','男','市场','员工',3000),
       (3,'关羽','男','市场','员工',4000),
       (4,'孙权','男','行政','总监',6000),
       (5,'周瑜','男','行政','员工',5000),
       (6,'小乔','女','行政','员工',4000),
       (7,'曹操','男','财务','总监',10000),
       (8,'司马懿','男','财务','员工',6000)
       );

查看所有部门

mysql> select dept from emp group by dept;

分组后,组里的详细记录就被隐藏起来了,不能直接查看,dept 分组就变成三条记录,每个组中会包含隐藏的记录,没办法显示,如果一定想显示的话,可以使用 group_concat(字段名),可以将多个值拼接为一个值:

mysql> select dept,group_concat(name) from emp group by dept;

注意:只有出现在 group by 后面的字段,才可以通过 select 显示出来,其他的都被隐藏了。在 mysql5.6分组后会默认显示每组的第一条记录,5.7不显示,因为5.7中sql_mode中就是ONLY_FULL_GROUP_BY

查看每个部分有多少人

mysql> select dept,count(name) from emp group by dept;

计算每个部门的平均薪资

mysql> select dept,avg(salary) from emp group by dept;

取别名

mysql> select dept,avg(salary) 平均工资 from emp group by dept;

image-20181122232527814

计算每个岗位的平均工资

mysql> select job,avg(salary) from emp group by job;

image-20181122232800382

计算每个部门每个岗位的平均工资

mysql> select dept,job,avg(salary) from emp group by dept,job;

image-20181122232930717

查询平均工资大于5000的部门

mysql> select dept from emp where avg(salary) > 5000;

这样写是不行的,因为 where 相当于一条条从文件中读取数据,而数据没有读取完是不能做平均值计算的,这时候就需要用 having 了。

having

对分组的数据进行过滤,作用与 where 相同,用于过滤。不通电在于,where 是从文件读取数据时的过滤条件,这导致了 where中不能使用聚合函数。

计算工资平均值大于5000的部门

mysql> select dept,avg(salary) from emp group by dept having avg(salary) > 5000;

image-20181122235836836

总结:select 语法是有执行顺序的,按照从左到右的顺序执行,所以 where 会在执行完成之前用不了聚合函数

查询岗位平均薪资高于6000的岗位名称和平均薪资

mysql> select job,avg(salary) from emp group by job having avg(salary) > 6000;

image-20181123000257688

查询部门人数少于3的部门名称人员名称和人员个数

mysql> select dept,group_concat(name),count(*) from emp group by dept having count(name) < 3; 

image-20181123000538071

order by

对结果排序

  • asc 表示升序,是默认的
  • desc 表示降序
  • by 后面可以有多个排序

按照工资排序

mysql> select * from emp order by salary;

image-20181123080220263

按照工资降序排序

mysql> select * from emp order by salary desc;

image-20181123080343839

按照工资升序 id 降序排序

mysql> select * from emp order by salary,id desc;

image-20181123080537034

按照工资升序 id 升序排序

mysql> select * from emp order by salary,id;

image-20181123080658050

limit

指定获取数据条数

使用方法:

​ limit a,b;表示从 a 开始不包括 a,获取 b 个数据。

mysql> select * from emp limit a,b;
mysql> select * from emp limit 2,2;

image-20181123081110942

分页查询计算页数

起始位置的算法

每页显示a条,现在是第 b 页,求起始位置

(b - 1) * a 

字符串拼接

image-20181122193726588

image-20181123000847643

完整的select语句

mysql> select [distinct] * from 表名
       [where
       group by
       having
       order by
       limit];

注意在书写时,必须按照这个顺序来写

正则表达式匹配

^ 匹配字段名称以’张’开头的数据

mysql> select * from emp where name regexp '^张';

image-20181123082232417

$ 匹配字段名称以’飞’结尾的数据

mysql> select * from emp where name regexp '飞$';

image-20181123082455838

. 匹配字段名称第二位后包含’飞’的数据,‘’.‘’表示任意字符

mysql> select * from emp where name regexp '.飞';

image-20181123082918332

[abci] 匹配字段名称中含有指定集合内容的人员

mysql> select * from emp where name regexp '[张飞关羽刘备]';

image-20181123185141222

[^alex] 匹配不符合集合中条件的内容,^表示取反

image-20181123185154564

注意1:^只有在[]内才是取反的意思,在别的地方都是表示从开始处匹配

注意2:简单理解 name regexp ‘[^alex]’ 等价于 name!=’alex’

‘a|x’ 匹配条件中的任意值

mysql> select * from emp where name regexp '张飞|关羽';

image-20181123185736287

查询以 张开头以飞结尾的数据

mysql> select * from emp where name regexp '^张.*飞$';

image-20181123185917271

MySQL 中使用 regexp 操作符来进行正则表达式匹配。

模式

^ 匹配输入字符串的开始位置

$ 匹配输入字符串的结束位置

. 匹配任何字符

[…] 字符集合。匹配所包含的任意一个字符。例如,'[abc]’ 可以匹配 ‘plain’ 中的 ‘a’

[^…] 负值字符集合。匹配未包含的任意字符。例如,'[^abc]’ 可以匹配 ‘plain’ 中的 ‘p’

p1|p2|p3 匹配 p1 或 p2 或 p3.例如,’z|food’ 能匹配 ‘z’ 或 ‘food’。'(z|f)ood’ 则匹配 ‘zood’ 或 ‘food’

多表查询

笛卡尔积查询

mysql> select * from 表1,...表n;

查询结果是将坐标中的每条记录与右表中的每条记录都关联以遍,假如 a 表有 m 条记录,b 表有 n 条记录,则笛卡尔积结果为 m*n。

数据准备

mysql> create table empl (id int,name char(10),sex char,dept_id int);
       insert empl values(1,"大黄","m",1);
       insert empl values(2,"老王","m",2);
       insert empl values(3,"老李","w",30);
mysql> create table deptl (id int,name char(10));
       insert deptl values(1,'市场');
       insert deptl values(2,'财务');
       insert deptl values(3,'行政');
mysql> select * from empl,deptl;

image-20181123192453808

因为笛卡尔积查询会产生很多错误数据,所以需要经过筛选出正确的关联关系。

mysql> select * from empl,deptl where empl.dept_id = deptl.id;

image-20181123193501507

内连接查询

就是笛卡尔积查询

mysql> select * from empl [inner] join deptl;

image-20181123193711910

加上筛选条件

mysql> select * from empl [inner] join deptl where empl.dept_id = deptl.id;

image-20181123193935956

左外连接查询

mysql> select * from empl left join deptl on empl.dept_id = deptl.id;

左表数据全部显示,右表只显示匹配上的数据。

image-20181123194338224

on 关键词和 where 关键词都是用于条件过滤,没有本质区别。在单表中 where 的作用是筛选过滤条件;在多表中 where 连接多表,满足条件就连接,不满足就不连接。于是为了区分单表还是多表换用了 on 关键词。只要是连接多表的条件就使用 on。

右外连接查询

mysql> select * from empl right join deptl on empl.dept_id = deptl.id;

右表数据全部显示,左表只显示匹配上的数据。

image-20181123194951654

内连接和外连接的理解:内指的是匹配上的数据,外指的是没匹配上的数据。

全外连接显示

mysql> select * from empl full join deptl on empl.dept_id = deptl.id; # mysql 不支持

合并查询结果(全外连接)

mysql> select * from empl left join deptl on empl.dept_id = deptl.id
       union
       select * from empl right join deptl on empl.dept_id = deptl.id;

image-20181123200300937

union 会去除重复数据,且只能合并字段数量相同的表;如果不想去除重复数据,使用 union all

mysql> select * from empl left join deptl on empl.dept_id = deptl.id
       union all
       select * from empl right join deptl on empl.dept_id = deptl.id;

image-20181123200703221

三表查询

数据准备

mysql> create table stul(id int primary key auto_increment,name char(10));
mysql> create table teal(id int primary key auto_increment,name char(10));

创建中间表

mysql> create table tsr(id int primary key auto_increment,
       t_id int,s_id int,
       foreign key(s_id) references stul(id),
       foreign key(t_id) references teal(id));
mysql> insert into stul values(null,'张三'),(null,'李四');
mysql> insert into teal values(null,'musibii'),(null,'thales');
mysql> insert into tsr values(null,1,1),(null,1,2)(null,2,2);

查询 musibii 教过那些学生

mysql> select * from stul join teal join tsr 
       on stul.id = tsr.s_id and teal.id = tsr.t_id where teal.name = 'musibii';

image-20181123204140888

多表查询总结:

  1. 把所有表连接起来
  2. 加上连接条件
  3. 如果有别的过滤条件,加上 where

子查询

当一个查询的结果是另一个查询的条件是,这个查询称之为子查询(内层查询)。

什么时候使用子查询?

当一次查询无法得到想要的结果时,需要多次查询。这样可以分多步查询减少查询的复杂度。

数据准备

mysql> create table emps(id int,name char(10),sex char,age int,dept_id int, job char(10),salary double);
mysql> insert into emps values
       (1,'刘备','男',26,1,'总监',5800),
       (2,'张飞','男',24,1,'员工',3000),
       (3,'关羽','男',30,1,'员工',4000),
       (4,'孙权','男',25,2,'总监',6000),
       (5,'周瑜','男',22,2,'员工',5000),
       (6,'小乔','女',31,2,'员工',4000),
       (7,'曹操','男',40,3,'总监',10000),
       (8,'司马懿','男',46,3,'员工',6000);
mysql> create table depts(id int primary key,name char(10));
mysql> insert into depts values(1,'市场'),(2,'行政'),(3,'财务');

查询市场部人员

mysql> select * from emps where dept_id = (select id from depts where name = '市场');

image-20181123211421700

子查询思路:

  1. 将一个复杂的问题 拆分为多个简单的问题
  2. 把一个复杂的查询 拆分为多个简单的查询

就比如查询部门人员:

  1. 查询部门 id
  2. 拿着 id 去员工表查询
mysql> select emps.name from emps join dept on dept.id = emps.dept_id where depts.name = '财务';

image-20181123211930985

查询平均年龄大于26的部门名称

mysql> select * from depts where id in (select dept_id from emps group by dept_id having avg(age) > 26);

image-20181123212448658

mysql> select depts.name from depts join emps on emps.dept_id = depts.id 
       group by depts.name having avg(age) > 26;

image-20181123212907673

exists 关键词查询

exists 后跟子查询,子查询有结果时为 True,没有结果是为 False,为 True 时外层执行,为 False 时外层不执行

mysql> select * from emps where exists(select * from emps where salary > 1000);

image-20181124091632042

综合练习

查询每个部门工资最高的员工信息

mysql> select * from emps join
       # 使用子查询得到每个部门的 id 以及部门的最高工资,形成一个虚拟表把原始表和虚拟表连接在一起
       (select dept_id,max(salary) as m from emps group by dept_id) as t1
       # 如果这个人的部门编号等于虚拟表中的部门编号,并且这个人的工资等于虚拟表中的最高工资,就是要找的数据
       on emps.dept_id = t1.dept_id and emps.salary = t1.m;

image-20181124101839921

版权声明:本文为zuanzuan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zuanzuan/p/10011200.html