首页 > 数据库 >盘点编写 sql 上的那些骚操作(针对mysql而言)

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

时间:2024-01-20 15:33:11浏览次数:39  
标签:goods mysql 代码 year month 盘点 2022 sql


前言

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

骚操作准备工作

准备如下这么一张数据表

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

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也是在一一对应着的,由于文具和手机对应的俩条数据被聚合成一条数据,所以我们可以使用聚合函数去操作这些字段

盘点编写 sql 上的那些骚操作(针对mysql而言)_数据库_02


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

盘点编写 sql 上的那些骚操作(针对mysql而言)_数据库_03


故最后的计算结果如下图

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

骚操作二, 深入理解 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,对应的结果也在下图一

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

骚操作三,深入理解 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 上的那些骚操作(针对mysql而言)_mysql_06

骚操作四 ,深入理解sql列

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

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

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

常规操作,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而言)_数据库_08

关于mysql中的异或条件查询,避坑!!!!

最近再改这么一个sql:查询企业前十排名,力度精确到省、市、区县。由于这个接口很多地方都用到了,考虑到接口的兼容性,入参、出参的格式也不好做改动,当时的入参是这样的,areaCode 有可能是区县代码、也可能是省市代码。因此我们在做逻辑查询的时候,查询条件必定少不了 “或” 查询。

{
    "year": "2022",
    "month": "7",
    "areaCode": "330110" //地区代码
}

当时就是很简单的在 where 后面加了个 or ,但是实际跑下来感觉到查出的数据有点不对劲,sql本意是想:当 area_code 传的是省市代码,查出 2022 年月份小于 7 并且 trade_type 为出口的省市数据,当 area_code 传的是区县代码,查出 2022 年月份小于 7 并且 trade_type 为出口的区县数据,但是细看如下 sql ,我们会发现当 area_code 传的是区县代码的时候,代码片段2在代码片段1中直接失效了,最终的查询条件只有这一个: district_code = 330110 生效,于是修改sql成代码片段3那样就可以达到sql本意了。在java编码中条件短路的情况很常见,到了sql中同样也需要我们注意一下!

代码片段1

WHERE
		`year` = 2022 
		AND `month` <= CAST( 7 AS UNSIGNED ) 
		AND trade_type = 'ck' 
		AND area_code = 330110 
		OR district_code = 330110

代码片段2

`year` = 2022 
		AND `month` <= CAST( 7 AS UNSIGNED ) 
		AND trade_type = 'ck' 
		AND area_code = 330110

代码片段3

WHERE
		`year` = 2022 
		AND `month` <= CAST( 7 AS UNSIGNED ) 
		AND trade_type = 'ck' 
		AND area_code = 330110 
		OR `year` = 2022 
		AND `month` <= CAST( 7 AS UNSIGNED ) 
		AND trade_type = 'ck' 
		AND district_code = 330110

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


标签:goods,mysql,代码,year,month,盘点,2022,sql
From: https://blog.51cto.com/u_16414043/9345741

相关文章

  • 如何防护网站存在的sql注入攻击漏洞
    SQL注入攻击是最危险的Web漏洞之一,危害性极大,造成的后果不堪设想,因此受到了大家的高度重视。那么你知道SQL注入攻击防范方法有哪些吗?SQL注入是一种网站的攻击方法。它将SQL代码添加到网站前端GETPOST参数中,并将其传递给mysql数据库进行分析和执行语句攻击。它是一种利用应用程序......
  • MYSQL-数据表基本
    1、创建表createtable表名(列名类型是否可以为空,列名类型是否可以为空)ENGINE=InnoDBDEFAULTCHARSET=utf82、删除表droptable表名3、清空表deletefrom表名truncatetable表名4、修改表添加列:altertable表名add列名类型删除列:alter......
  • MySQL 视图
    视图(View)是一种虚拟存在的表,视图中的数据并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。创建CREATE[......
  • MYSQL自增步长
    1、对于自增列,必须是索引(含主键)。2、对于自增可以设置步长和起始值基于会话级别:showsessionvariableslike'auto_inc%';查看全局变量setsessionauto_increment_increment=2;设置会话步长#setsessio......
  • dotnet 多数据库 sqlite efcore model和entity区别 一对多 多对一 多对多
    efcore-multi-db/MultiDb.slnMicrosoftVisualStudioSolutionFile,FormatVersion12.00#VisualStudio15VisualStudioVersion=15.0.27130.2024MinimumVisualStudioVersion=10.0.40219.1Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}")="......
  • SQL优化
    1、Insert优化批量插入(一次也不宜太多,500~1000,根据业务情况决定),避免频繁开启、关闭事务手动提交事务主键顺序插入(性能高于乱序插入)大批量的数据插入如果一次性需要插入大批量数据,使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入  2、主键优......
  • Hive SQL底层执行过程详细剖析
     本文结构采用宏观着眼,微观入手,从整体到细节的方式剖析HiveSQL底层原理。第一节先介绍Hive底层的整体执行流程,然后第二节介绍执行流程中的SQL编译成MapReduce的过程,第三节剖析SQL编译成MapReduce的具体实现原理。HiveHive是什么?Hive是数据仓库工具,再具体点就......
  • MySQL中的加密函数
    本文简单介绍MySQL中的加密函数。MySQL提供了多种加密函数,以下是一些常用的:PASSWORD(str):用于密码加密,通常用于创建用户时对密码进行加密。MD5(str):生成一个128位的加密串,返回一个32位的16进制数。SHA1(str):生成一个160位的加密串,返回一个40位的16进制数。ENCODE(str......
  • SQLServer 分页查询
    SQLServer分页查询方式TOP子句--每页20条记录,第1页selecttop20*fromtceshiorderbyID--第2页(返回ID不是前20条记录)selecttop20*fromtceshiwhereIDnotin(selecttop20IDfromtceshiorderbyID)orderbyIDROW_NUMBER语法[ROW_NUMBER()O......
  • SQL常见面试题(测试工程师)
    用一条 SQL 语句 查询出每门课都大于 60 分的学生姓名。表 scores 如下SELECTname,MIN(score)ashigtfromstudent_scoressgroupbynameHAVINGhigt>60用一条 SQL 语句 查询两门以上不及格课程的同学的学号姓名以及其平均成绩, 并按成绩排序SELECT......