盘点编写 sql 上的那些骚操作(针对mysql而言)

Posted 张子行的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了盘点编写 sql 上的那些骚操作(针对mysql而言)相关的知识,希望对你有一定的参考价值。

前言

咋说呢,最近交接了一个XXX统计系统到我手上,点进去系统主页,看了下实现了哪些功能,页面看着很简单就那么几个统计模块,本来想着就那么几张报表的crud来着,看了下代码也还好体量也不大,于是乎美滋滋的随波逐流了,后来出现了一个bug说什么数据统计的不对,想着快速给他改掉,顺着控制层,一路摸索到mapper这,点进xml文件一看,好家伙我尼玛一个统计sql 400多行,故事的正片由此开始!

骚操作准备工作

准备如下这么一张数据表


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '商品编号',
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '商品名称',
  `price` double DEFAULT NULL COMMENT '商品单价',
  `year` int DEFAULT '0' COMMENT '商品库存',
  `month` int DEFAULT NULL COMMENT '商品类型',
  `type` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '类别',
  `rate` int DEFAULT '1' COMMENT '利率',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8;

BEGIN;
INSERT INTO `goods` VALUES (1, '00002', 2, 2022, 2, '文具', 2);
INSERT INTO `goods` VALUES (2, '00002', 22, 2022, 2, '手机', 22);
INSERT INTO `goods` VALUES (3, '00003', 3, 2022, 4, '电脑', 3);
INSERT INTO `goods` VALUES (4, '00003', 33, 2022, 4, '毛巾', 33);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;


骚操作一,深入理解 SUM()

求2022年各个月的营收,模拟环境:每种商品对应的利率可能都是不一样的,实际环境中可能 rate 字段会用一张独立的表去存储,那时的sql可能会更加复杂,此案例的列觉只为帮助大家更好的理解,sum 函数底层的执行过程

select year,month,sum(price*rate) sum from goods group by `year`,`month`;

由于写法是 sum(price*rate) 故分组后的中间状态是这样的,如下图一。根据 year、month 分组聚和成了如下这么俩条数据,那些未被聚合的字段比如:price、rate、type也是在一一对应着的,由于文具和手机对应的俩条数据被聚合成一条数据,所以我们可以使用聚合函数去操作这些字段

sum(price*rate) ,中间过程如下图,先是找到每一条数据的price乘对应的rate,然后才是累加操作

故最后的计算结果如下图

骚操作二, 深入理解 HAVING

追加需求:求2022年营收超过500的月份是哪个月?
骚操作一已经统计出来了各个月的营收,求超过500的营收是哪个月份只需对骚操作一的结果进行一个筛选就好了,先来列举常规几种操作

  1. 在代码中进行一个筛选
  2. 对骚操作一做一个子查询,然后使用 where 做一个数据筛选
 select * from (select year,month,sum(price*rate) sum from goods group by `year`,`month`)a where a.sum>500;
  1. 使用 HAVING,对上点 2 做一个优化,下图俩条 sql 执行结果都一样

普及一下 HAVING 的用法:

  • 对已经生成的结果级进行一个筛选,筛选条件只局限结果级中存在的列,何为结果级?举个例子:就是 where、group by 都已经作用过得到的结果,此时如果还想对数据做一个筛选,就可以用 having。

如果有的小伙伴还对 having 有点陌生,可以重点分析下下图一的第二条sql,对应的结果也在下图一

骚操作三,深入理解 CONCAT()

求2022年2月到2022年5月的所有数据,但是年、月是分俩个字段存储的

select *,CONCAT(year,month) date from goods where CONCAT(year,month)>='20222' and CONCAT(year,month)<='20225';

打破思维误区!直接在查询条件使用 CONCAT 函数拼接字段进行查询,就可以了,查询 sql 以及返回结果如下图一

骚操作四 ,深入理解sql列

在查出的结果级上面手动的添加一列,并赋予默认值,基本没咋用到,图一乐就行

select name,'自定义填充数据' customDate from goods GROUP BY name;

常规操作,IF、IFNULL、ROUND

这俩个函数也非常实用,当某些字段为null的时候,可以自定义一些默认值。ROUND(a,b),为 a 保留 b 位小数。

select id,if(id=1,'-',id),IFNULL(id,0),ROUND(id/100,4) from goods;

后面还有别的骚操作,本文会陆续更新~

以上是关于盘点编写 sql 上的那些骚操作(针对mysql而言)的主要内容,如果未能解决你的问题,请参考以下文章

盘点 Chrome 开发者工具的那些骚技巧

SQL注入之骚姿势小记

掌握 MySQL 这 19 个骚操作,效率至少提高3倍

「推荐收藏!」MySQL技术之旅总结和盘点优化方案系列之常用SQL的优化

#yyds干货盘点#盘点MySQL中的那些日志文件

如何在命令长度受限的情况下成功get到webshell(函数参数受限突破mysql的骚操作)