首页 > 其他分享 >过滤条件之分组 group by、having、distinct、order by、limit、正则、多表查询和子查询、笛卡尔积

过滤条件之分组 group by、having、distinct、order by、limit、正则、多表查询和子查询、笛卡尔积

时间:2024-06-12 21:34:01浏览次数:27  
标签:group -- 查询 dep emp 多表 post id select

【一】过滤条件之分组 group by

【1】引入

-- 按照指定条件对所有数据进行分组
-- 对员工进行分组 按照年龄 / 部门 
-- ...
select * from * where * group by *;

【2】按照部门分组

(1)查询数据

select * from emp group by post;
# 第一次使用部门分组会报错

mysql> select * from emp group by post;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY...

(2)解决办法

-- 关闭严格模式
-- 首先模糊查询所有严格模式
show variables like "%mode";

-- 替换严格模式
-- 删除了 ONLY_FULL_GROUP_BY
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';

-- 重新进客户端,否则不生效
show variables like "%mode";

  • 查询数据
select * from emp group by post;

  • 拿到每一个部门的第一行数据

【3】聚合函数

-- 聚合函数 ---》min / max / avg / count ...
-- 查询当前每个分组下的最高信息 max
select post,max(salary) from emp group by post;

# 输出结果
mysql> select post,max(salary) from emp group by post;
+-----------+-------------+
| post      | max(salary) |
+-----------+-------------+
| operation |      630.33 |
| professor |     1000.10 |
| sale      |      420.33 |
| teacher   |    15000.99 |
+-----------+-------------+

【4】定制化字段显示内容

-- 有时候想自定制显示的信息
-- 定制化字段显示的内容
select post,max(salary) as "最高薪资" from emp group by post; 

# 输出结果
mysql> select post,max(salary) as "最高薪资" from emp group by post;
+-----------+--------------+
| post      | 最高薪资     |
+-----------+--------------+
| operation |       630.33 |
| professor |      1000.10 |
| sale      |       420.33 |
| teacher   |     15000.99 |
+-----------+--------------+

【5】查询每个部门下的最低薪资 min

select post,min(salary) as "最低薪资" from emp group by post;

# 输出结果
mysql> select post,min(salary) as "最低薪资" from emp group by post;
+-----------+--------------+
| post      | 最低薪资     |
+-----------+--------------+
| operation |       330.62 |
| professor |      1000.10 |
| sale      |       300.13 |
| teacher   |     11000.80 |
+-----------+--------------+

【6】查询每个部门下的平均年龄avg

select post,avg(age) as "平均年龄" from emp group by post;

# 输出结果
mysql> select post,avg(age) as "平均年龄" from emp group by post;
+-----------+--------------+
| post      | 平均年龄     |
+-----------+--------------+
| operation |      47.8000 |
| professor |      20.0000 |
| sale      |      48.1667 |
| teacher   |      29.8000 |
+-----------+--------------+

【7】查询每个部门下的总薪资sum

select post,sum(salary) as "总薪资" from emp group by post;

# 输出结果
mysql> select post,sum(salary) as "总薪资" from emp group by post;
+-----------+-----------+
| post      | 总薪资    |
+-----------+-----------+
| operation |   2132.33 |
| professor |   1000.10 |
| sale      |   2173.45 |
| teacher   |  65003.61 |
+-----------+-----------+

【8】查询每个部门下的平均薪资avg

select post as "部门",avg(salary) as "平均薪资" from emp group by post;

# 输出结果
mysql> select post as "部门",avg(salary) as "平均薪资" from emp group by post;
+-----------+--------------+
| 部门      | 平均薪资     |
+-----------+--------------+
| operation |   426.466000 |
| professor |  1000.100000 |
| sale      |   362.241667 |
| teacher   | 13000.722000 |
+-----------+--------------+

【9】查询每个部门下的人数count

select post as '部门',count(id) as '总人数' from emp group by post;

# 输出结果
mysql> select post as '部门',count(id) as '总人数' from emp group by post;
+-----------+-----------+
| 部门      | 总人数    |
+-----------+-----------+
| operation |         5 |
| professor |         1 |
| sale      |         6 |
| teacher   |         5 |
+-----------+-----------+
  • count 函数不能对 null 进行计数
-- count 函数不能对 null 进行计数 ,计数为 0
select post,count(post_comment) as "总人数" from emp group by post;

# 输出结果
mysql> select post,count(post_comment) as "总人数" from emp group by post;
+-----------+-----------+
| post      | 总人数    |
+-----------+-----------+
| operation |         0 |
| professor |         0 |
| sale      |         0 |
| teacher   |         0 |
+-----------+-----------+

【10】查询分组之后的部门名称和每个部门下所有的员工姓名(group_concat)

-- 查询分组之后的部门名称以及每个部门下的所有成员的名字
-- group_concat : 获取到分组之后具体的字段的值
select post,group_concat(name) from emp group by post;

select post,group_concat(name) as "人员名单" from emp group by post;

# 输出结果
mysql> select post,group_concat(name) as "人员名单" from emp group by post;
+-----------+-------------------------------------------+
| post      | 人员名单                                  |
+-----------+-------------------------------------------+
| operation | 大古,张三,李四,王五,赵六                  |
| professor | chosen                                    |
| sale      | 娜娜,芳芳,小明,亚洲,华华,田七             |
| teacher   | mengmeng,xiaomeng,xiaona,xiaoqi,suimeng   |
+-----------+-------------------------------------------+
-- group_concat :不仅仅只是能获取当前分组下的所有数据还可以支持字符串拼接操作.
select post,group_concat(name,'_saler') as "人员名单" from emp group by post;

# 输出结果
mysql> select post,group_concat(name,'_saler') as "人员名单" from emp group by post;
+-----------+-------------------------------------------------------------------------------+
| post      | 人员名单                                                                      |
+-----------+-------------------------------------------------------------------------------+
| operation | 大古_saler,张三_saler,李四_saler,王五_saler,赵六_saler                        |
| professor | chosen_saler                                                                  |
| sale      | 娜娜_saler,芳芳_saler,小明_saler,亚洲_saler,华华_saler,田七_saler             |
| teacher   | mengmeng_saler,xiaomeng_saler,xiaona_saler,xiaoqi_saler,suimeng_saler         |
+-----------+-------------------------------------------------------------------------------+
-- 支持查询个人的多条数据
select post,group_concat(name,'_saler','|',salary) as "人员名单" from emp group by post;

【11】查询数据(不分组之前用 concat)

-- group_concat:必须分组之后才能使用,否则会乱掉
select group_concat("NAME:",name) as "姓名",age from emp;

-- concat :不分组的情况下对每一个字段进行定制
select concat("NAME:",name)as "姓名",age from emp;
-- 只能按照单个字段进行取值,不允许使用 * 代替后面的所有字段,否则会报错。

【12】每一个人一年 13薪的薪资

-- 如果想要查询每一个人一年 13薪的薪资
select name,salary*13 as "年薪" from emp;

【13】where 和 group by

(1)关键字 where 和 group by 同时出现

  • 关键字 where 和 group by 同时出现的时候,group by 必须在 where 后面

    • where 先对整体数据进行过滤
    • group by 再对数据进行分组

(2)where 删选条件不能使用聚合函数

  • where 筛选条件不能使用聚合函数

    • 不分组,默认整张表就是一组
  • 聚合函数只能在分组之后使用

    • 查询数据
select id,name,age from emp where max(salary)>3000;
# 报错
-- ERROR 1111 (HY000): Invalid use of group function

-- 查询数据
select max(salary) from emp;

【14】统计各部门年龄在 30 岁以上的员工的平均薪资

-- 统计各部门年龄在 30 岁以上的员工的平均薪资
-- 统计各部门 分组
-- 年龄在 30 岁以上 过滤
-- 平均薪资 聚合函数 avg

-- 先过滤30岁以上的人
select * from emp where age>30;
-- 在对 30 岁以后的人进行分组
select * from emp where age>30 group by post;
-- 在对 30 岁以后的人进行分组 计算平均薪资
select post as "部门",avg(salary) as "平均薪资" from emp where age>30 group by post;

【二】过滤条件之having

  • having与where的功能是一模一样的 都是对数据进行筛选

    • where用在分组之前的筛选
    • havng用在分组之后的筛选
  • 只不过having是在分组之后进行的过滤操作

  • 即having是可以直接使用聚合函数的

-- 统计各部门年龄在30岁以上的员工的工资
-- 并且保留平均薪资大于1W的部门

-- 统计各部门 分组
-- 在 30 岁以上的员工 where 过滤
-- 平均薪资大于1w avg(salary)>10000
select post,avg(salary) from emp where age>30 group by post;

-- having:分组之后再进行筛选
select post,avg(salary) from emp where age>30 group by post having avg(salary)>10000;

【三】过滤条件之去重 distinct

  • 必须是完全一样的数据才可以去重
  • 一定要注意主键的问题
  • 在主键存在的情况下是一定不可能去重的
-- 将该字段下的重复的数据进行去重  --- 集合
-- 我们的表中的主键ID 自增 唯一 不为空
select distinct id,age from emp;

-- 去除一样的数据 ---> 去除除主键外的数据
select distinct gender from emp;

【四】过滤条件之排序 order by

  • order by : 默认是升序
  • asc 默认可以省略不写 ---> 修改降序
  • desc : 降序
-- 将表中的薪资按照从小到大排序:升序
select * from emp order by salary;

-- 降序
select * from emp order by salary desc;

-- 按照薪资(升序)和年龄(降序)排序
select * from emp order by salary asc,age desc;

-- 统计各部门年龄在 30 岁以上的员工的工资
-- 并且保留平均薪资大于100的部门
-- 对平均工资进行排序
select post as "部门",avg(salary) as "平均薪资" from emp 
where age>30 
group by post 
having avg(salary)>100 
order by avg(salary) asc;

【五】过滤条件之限制数据量 limit

-- 限制获取到的数据的前10条
select * from emp limit 10;
-- 增加额外的参数进行限制,实现分页的效果
-- 索引位置是从0开始的
-- limit 索引位置,数据量

-- 从索引第6的位置开始获取数据,获取后5条数据(不顾头,顾尾)
select * from emp limit 5,5;
-- 从索引第7的位置开始获取数据,获取后10条数据;
select * from emp limit 6,10;

-- 查询工资最高的人的详细信息
select * from emp order by salary desc;

-- 只要最高的那个人的信息
select * from emp order by salary desc limit 1;

【六】过滤条件之正则表达式

DROP TABLE IF EXISTS person;

create table person(
	name varchar(32) character set utf8 collate utf8_general_ci null default null,
    age int(40) null default null,
    heigh int(40) null default null,
    sex varchar(255) character set utf8 collate utf8_general_ci null default null
) engine = InnoDB character set = utf8 collate = utf8_general_ci row_format = Dynamic;

INSERT INTO `person` VALUES ('Thomas ', 25, 168, '男');
INSERT INTO `person` VALUES ('Tom ', 20, 172, '男');
INSERT INTO `person` VALUES ('Dany', 29, 175, '男');
INSERT INTO `person` VALUES ('Jane', 27, 171, '男');
INSERT INTO `person` VALUES ('Susan', 24, 173, '女');
INSERT INTO `person` VALUES ('Green', 25, 168, '女');
INSERT INTO `person` VALUES ('Henry', 21, 160, '女');
INSERT INTO `person` VALUES ('Lily', 18, 190, '男');
INSERT INTO `person` VALUES ('LiMing', 19, 187, '男');
选项 说明 例子 匹配值示例
^ 匹配文本的开始字符 ‘^b’ 匹配以字母 b 开头的字符串 book、big、banana、bike
$ 匹配文本的结束字符 ‘st$’ 匹配以 st 结尾的字符串 test、resist、persist
. 匹配任何单个字符 ‘b.t’ 匹配任何 b 和 t 之间有一个字符 bit、bat、but、bite
* 匹配前面的字符 0 次或多次 ‘f*n’ 匹配字符 n 前面有任意个字符 f fn、fan、faan、abcn
+ 匹配前面的字符 1 次或多次 ‘ba+’ 匹配以 b 开头,后面至少紧跟一个 a ba、bay、bare、battle
? 匹配前面的字符 0 次或1次 ‘sa?’ 匹配0个或1个a字符 sa、s
字符串 匹配包含指定字符的文本 ‘fa’ 匹配包含‘fa’的文本 fan、afa、faad
[字符集合] 匹配字符集合中的任何一个字符 ‘[xz]’ 匹配 x 或者 z dizzy、zebra、x-ray、extra
[^] 匹配不在括号中的任何字符 ‘[^abc]’ 匹配任何不包含 a、b 或 c 的字符串 desk、fox、f8ke
字符串 匹配前面的字符串至少 n 次 ‘b{2}’ 匹配 2 个或更多的 b bbb、bbbb、bbbbbbb
字符串 匹配前面的字符串至少 n 次, 至多 m 次 ‘b{2,4}’ 匹配最少 2 个,最多 4 个 b bbb、bbbb
-- 查询 name 字段以j开头的记录
select * from person where name regexp '^j';

-- 查询 name 字段以“y”结尾的记
select * from person where name REGEXP 'y$';

-- 查询 name 字段值包含“a”和“y”,且两个字母之间只有一个字母的记录
select * from person where name REGEXP 'a.y';

-- 查询 name 字段值包含字母“T”,且“T”后面出现字母“h”的记录
select * from person where name REGEXP 'Th*';

-- 查询 name 字段值包含字母“T”,且“T”后面至少出现“h”一次的记录
select * from person where name REGEXP 'Th+';

-- 查询 name 字段值包含字母“S”,且“S”后面出现“a”一次或零次的记录
select * from person where name REGEXP  'sa?';

【七】多表查询和子查询

-- 多表查 又称为连表查询 多张表放到一起去查询数据
-- 员工表和部门表 : 把员工表和部门表合并成一张表 ---> 在合并后的表中查询数据
id name dep_id dep_name desc 
1  chosen   1   cook      后勤


-- 子查询
-- 先查一条数据,将这条数据的结果作为下一条查询语句的起始
-- 先在员工表中查询数据 查询 dream 的dep_id
员工表 
# id name dep_id
   1  dream  1

-- 再拿着上面的dep_id 在部门表中查询到 name
# 部门表
id name desc 
1   后勤  后勤
create table dep(
	id int PRIMARY KEY AUTO_INCREMENT,
    name varchar(20)
);


create table emp_two (
    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","运营部"),
("204","售后部");

insert into emp_two(name,sex,age,dep_id) values
("chosen","male",18,200),
("max","female",18,201),
("menmgneg","male",38,202),
("hope","male",18,203),
("own","male",28,204),
("thdream","male",18,205);
-- 获取员工chosen所在的部门名称

-- 先在员工表中获取到当前员工对应的部门ID
select dep_id from emp_two where name="chosen";

-- 再根据部门ID去部门表中查询部门名称
select name from dep where id =200;

-- 结合
select name from dep where id =(select dep_id from emp_two where name="chosen");

# 输出结果
mysql> select name from dep where id =(select dep_id from emp_two where name="chosen");
+-----------+
| name      |
+-----------+
| 技术部    |
+-----------+
-- 根据部门ID去查当前这个人的详细信息
select id from dep where name="技术部";

select * from emp_two where dep_id in(select id from dep where name="技术部");

# 输出结果
mysql> select * from emp_two where dep_id in(select id from dep where name="技术部");
+----+--------+------+------+--------+
| id | name   | sex  | age  | dep_id |
+----+--------+------+------+--------+
|  1 | chosen | male |   18 |    200 |
+----+--------+------+------+--------+

【八】笛卡尔积

  • 在SQL中,当我们使用JOIN操作将两个或更多的表连接在一起时,结果集中的行数是所有连接表的行数的乘积。这就是所谓的笛卡尔积。
  • 例如,假设我们有两个表A和B,其中A有5行,B有3行。
  • 如果我们使用INNER JOIN将这两个表连接起来,那么结果集中将会有5 x 3 = 15行。
  • 这是因为对于每一行A,我们可以从B中选择任意一行进行匹配。
  • 因此,总共有5种不同的方式来组合A表中的每一行和B表中的每一行,这导致了最终结果集的大小为5 x 3 = 15。
  • 这个过程就是笛卡尔积,它是数学中的一种运算,用于计算两个集合的所有可能的元素组合的数量。
  • 在这个情况下,每个元素都是一个表格中的行。
  • 所以,当我们在MySQL中使用JOIN操作时,结果集的大小实际上是所有连接表的行数的乘积,这就是为什么我们称其为笛卡尔积的原因。
-- 根据笛卡尔积进行品表 一共有 30 行数据
select * from dep,emp_two;

-- 基于笛卡尔积进行品表 
-- 再对品表进行过滤
-- 员工表中的部门ID=部门表中ID 的数据
-- 拼接数据过滤的时候必须是二者ID相等才会被保留
select * from dep,emp_two where emp_two.dep_id = dep.id;

# 输出结果
mysql> select * from dep,emp_two where emp_two.dep_id = dep.id;
+-----+--------------+----+----------+--------+------+--------+
| id  | name         | id | name     | sex    | age  | dep_id |
+-----+--------------+----+----------+--------+------+--------+
| 200 | 技术部       |  1 | chosen   | male   |   18 |    200 |
| 201 | 人力资源     |  2 | max      | female |   18 |    201 |
| 202 | 销售部       |  3 | menmgneg | male   |   38 |    202 |
| 203 | 运营部       |  4 | hope     | male   |   18 |    203 |
| 204 | 售后部       |  5 | own      | male   |   28 |    204 |
+-----+--------------+----+----------+--------+------+--------+

【九】多表查询和子查询(案例)

-- 内连接 inner join 并集
-- 只有两张表都有的数据才会被保留

-- 左连接 left join 
-- 只有左面表都有的数据才会被保留

-- 右连接 right join
-- 只有右面表都有的数据才会被保留

-- 全连接 left join... union right join ...;
-- 两张表不管有没有全都拼上去
-- 内连接  inner join
select * from dep inner join emp_two on emp_two.dep_id = dep.id;

# 输出结果
mysql> select * from dep inner join emp_two on emp_two.dep_id = dep.id;
+-----+--------------+----+----------+--------+------+--------+
| id  | name         | id | name     | sex    | age  | dep_id |
+-----+--------------+----+----------+--------+------+--------+
| 200 | 技术部       |  1 | chosen   | male   |   18 |    200 |
| 201 | 人力资源     |  2 | max      | female |   18 |    201 |
| 202 | 销售部       |  3 | menmgneg | male   |   38 |    202 |
| 203 | 运营部       |  4 | hope     | male   |   18 |    203 |
| 204 | 售后部       |  5 | own      | male   |   28 |    204 |
+-----+--------------+----+----------+--------+------+--------+
-- 左连接 left join
select * from dep left join emp_two on emp_two.dep_id = dep.id;

-- 右连接 right join
select * from dep right join emp_two on emp_two.dep_id = dep.id;

-- 全连接 left join... union right join ...;
select * from dep left join emp_two on emp_two.dep_id = dep.id union select * from dep right join emp_two on emp_two.dep_id = dep.id;

-- 查询平均年龄在25岁以上的部门名称

-- 方案一:
-- 先查员工表 分组 取均值 过滤 剩下部门ID
select dep_id from emp_two group by dep_id having avg(age)>25; 

-- 再去部门表中根据部门ID查部门名称
select * from dep where id in (select dep_id from emp_two group by dep_id having avg(age)>25);

# 输出结果
+-----+-----------+
| id  | name      |
+-----+-----------+
| 202 | 销售部    |
| 204 | 售后部    |
+-----+-----------+
-- 方案二:联表查
-- 先拼表 ---> 过滤 在计算
select * from emp_two inner join dep on emp_two.dep_id=dep.id;

select dep.name from emp_two inner join dep 
on emp_two.dep_id = dep.id
group by dep.name
having avg(age) > 25
;

标签:group,--,查询,dep,emp,多表,post,id,select
From: https://www.cnblogs.com/chosen-yn/p/18244726

相关文章

  • 树型表查询
    树型表查询在开发中,很常见的会用到树形结构,以课程分类结构,其在数据库中的表示如下:通常都是通过parentId来描述父亲节点。查询方式有两种:固定层级查询、递归查询1、固定层级查询如果树的层级固定可以使用表的自链接去查询,比如:我们只查询两级课程分类,可以用下边的SQLSELECT......
  • MybatisPlus - [04] 分页查询
    limitm,n、PageHelper、MyBatisPlus分页插件 一、拦截器分页(1)在MybatisPlusConfig中进行配置@BeanpublicMybatisPlusInterceptorpaginationInterceptor(){MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();interceptor.addInnerIntercep......
  • 在WEPAPI接口无法查询物料分组
     数据分组仅有业务对象没有实体表, 所以接口不能直接访问数据分组BOS_FORMGROUP通过表名反查业务对象标识,接口中使用查询到的业务对象标识可正常查询到数据.注意:可能存在分组没有对应的业务对象的情况,此时需要新建业务对象并设置对应的分组表. ......
  • 【FreeRTOS】事件组 event group(附源码)
    引言:事件组是一种用于同步多个任务之间的状态和行为的机制。在操作系统中,事件组通常由操作系统提供,用于实现任务间的通信和同步。事件组通常包含一组独立的事件或标志,每个事件或标志都可以表示一种特定的状态或条件。任务可以等待事件组中的一个或多个事件被设置,也可以设置、......
  • presto 查询调度流程 (Coordinator Scheduler)
    basedontag:0.287presto的scheduler是SqlQueryScheduler这个类控制的,这个class主要是负责调度物理执行计划。调度具体的每个SqlStageExecution.这个Stage可以当成Fragment的一个概念他会先把所有的stage创建一个schedule计划。一共有两种schedule计划,一个是all-at-on......
  • ClickHouse内幕(3)基于索引的查询优化
    ClickHouse索引采用唯一聚簇索引的方式,即Part内数据按照orderbykeys有序,在整个查询计划中,如果算子能够有效利用输入数据的有序性,对算子的执行性能将有巨大的提升。本文讨论ClickHouse基于索引的查询算子优化方式。在整个查询计划中Sort、Distinct、聚合这3个算子相比其他算子......
  • Mybatis的查询功能
    MyBatis的各种查询功能如果查询出的数据只有一条,可以通过实体类对象接收List集合接收Map集合接收,如结果{password=123456,sex=男,id=1,age=23,username=admin}如果查询出的数据有多条,一定不能用实体类对象接收,会抛异常TooManyResultsException,可以通过实体类类型......
  • 情景题之小明的Linux实习之旅:linux实战练习1(上)【基础命令,权限修改,日志查询,进程管理...
    小明的Linux实习之旅:基础指令练习情景练习题背景介绍场景1:初识Linux,创建目录和文件场景2:权限管理,小明的权限困惑场景3:打包与解压,小明的备份操作场景4:使用Grep,小明的搜索技能场景5:系统服务管理,小明的首次接触场景6:进程管理,小明的多任务处理场景7:定时任务与系统状态场景8:d......
  • 如何判断 是否 需要 CSS 中的媒体查询
    以下是一些常见的使用媒体查询的场景:响应式布局:当设备的屏幕尺寸变化时,我们可以使用媒体查询来调整布局,以适应不同的屏幕尺寸。设备特性适配:我们可以使用媒体查询来检测设备的特性,如设备方向、分辨率、颜色能力等,并根据这些特性来应用不同的样式。优化打印样式:我们可......
  • 微信小程序源码-公交信息在线查询系统的计算机毕业设计(附源码+演示录像+LW)
    大家好!我是职场程序猿,感谢您阅读本文,欢迎一键三连哦。......