ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

sql 行转列 日周月 图表统计

sql 行转列 日周月 图表统计

目录

目录

需求

准备

分析

按月分组

行转列

错误版本

正确版本

分析

行转列

分析

按周分组

行转列

本年


需求

页面有三个按钮  日周月,统计一周中每天(日),一月中每周(周),一年中每月(月),设备台数

点击 按钮月,出现类似下图这种

返回给前端,如果某个月份没有数据,x轴该月份不是没有了嘛,当然可以有其他方式来解决,本文主要讲下行转列

准备

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for robot
-- ----------------------------
DROP TABLE IF EXISTS `robot`;
CREATE TABLE `robot`  (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`createtime` datetime NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of robot
-- ----------------------------
INSERT INTO `robot` VALUES (1, '1号机器人', '2024-02-02 23:07:37');
INSERT INTO `robot` VALUES (2, '2号机器人', '2024-01-01 23:07:37');
INSERT INTO `robot` VALUES (3, '3号机器人', '2024-02-02 23:07:37');
INSERT INTO `robot` VALUES (4, '4号机器人', '2024-01-01 15:41:42');
INSERT INTO `robot` VALUES (5, '5号机器人', '2024-03-03 15:51:25');
INSERT INTO `robot` VALUES (6, '6号机器人', '2024-01-26 11:34:46');SET FOREIGN_KEY_CHECKS = 1;

注:此处举例都是同一年,其他年份where过滤一下即可,过滤方式于文章末尾

分析

需要按照月去统计,那么将相同月合为一组,统计ID为数量即可,那月怎么划分?

从第6位开始后两位即为月,SUBSTRING(createtime, 6, 2)

按月分组

SELECT SUBSTRING(createtime, 6, 2) dayOfMonth, count(ID) num
FROM `robot`
GROUP BY SUBSTRING(createtime, 6, 2)

行转列

错误版本

select
case when dayOfMonth = 1 then num else 0 end January,
case when dayOfMonth = 2 then num else 0 end February,
case when dayOfMonth = 3 then num else 0 end March,
case when dayOfMonth = 4 then num else 0 end April,
case when dayOfMonth = 5 then num else 0 end May,
case when dayOfMonth = 6 then num else 0 end June,
case when dayOfMonth = 7 then num else 0 end July,
case when dayOfMonth = 8 then num else 0 end August,
case when dayOfMonth = 9 then num else 0 end September,
case when dayOfMonth = 10 then num else 0 end October,
case when dayOfMonth = 11 then num else 0 end November,
case when dayOfMonth = 12 then num else 0 end December
from (SELECT SUBSTRING(createtime, 6, 2) dayOfMonth, count(ID) numFROM `robot`GROUP BY SUBSTRING(createtime, 6, 2)
) t

????????????   

咋就成这样了,难不成每次 case when 同一个字段 end 不同字段 时他会将之前的结果表每行都扫描一次?那我取有值的一次是不是就解决了?怎么取?有值的那次是最大的

正确版本

select
MAX(case when dayOfMonth = 1 then num else 0 end) January,
MAX(case when dayOfMonth = 2 then num else 0 end) February,
MAX(case when dayOfMonth = 3 then num else 0 end) March,
MAX(case when dayOfMonth = 4 then num else 0 end) April,
MAX(case when dayOfMonth = 5 then num else 0 end) May,
MAX(case when dayOfMonth = 6 then num else 0 end) June,
MAX(case when dayOfMonth = 7 then num else 0 end) July,
MAX(case when dayOfMonth = 8 then num else 0 end) August,
MAX(case when dayOfMonth = 9 then num else 0 end) September,
MAX(case when dayOfMonth = 10 then num else 0 end) October,
MAX(case when dayOfMonth = 11 then num else 0 end) November,
MAX(case when dayOfMonth = 12 then num else 0 end) December
from (SELECT SUBSTRING(createtime, 6, 2) dayOfMonth, count(ID) numFROM `robot`GROUP BY SUBSTRING(createtime, 6, 2)
) t

分析

需要一个函数帮我确定给定的日期是星期几,然后再分组统计

SELECT DAYNAME(createtime) dayOfWeek, count(ID) num	
FROM `robot` 
GROUP BY DAYNAME(createtime) 

行转列

select
MAX(case when dayOfWeek = 'Monday' then num else 0 end) Monday,
MAX(case when dayOfWeek = 'Tuesday' then num else 0 end) Tuesday,
MAX(case when dayOfWeek = 'Wednesday' then num else 0 end) Wednesday,
MAX(case when dayOfWeek = 'Thursday' then num else 0 end) Thursday,
MAX(case when dayOfWeek = 'Friday' then num else 0 end) Friday,
MAX(case when dayOfWeek = 'Saturday' then num else 0 end) Saturday,
MAX(case when dayOfWeek = 'Sunday' then num else 0 end) Sunday
from (SELECT DAYNAME(createtime) dayOfWeek, count(ID) num	FROM `robot` GROUP BY DAYNAME(createtime) 
) t

公司要求的是:

1-7号固定为第一周,8-14号固定为第二周,15-21固定为第三周,剩下的为第四周

注:如果不是这种规则,网上找找周相关函数,很容易找到的

分析

需要按照他们定的规则划分周,那我怎么知道日期几号?

SUBSTRING(createtime, 9, 2)    9号位置开始后两位为天

按周分组

	SELECT CASE WHEN SUBSTRING(createtime, 9, 2) <= 7 THEN 'firstWeek'WHEN SUBSTRING(createtime, 9, 2) <= 14 THEN 'secondWeek'WHEN SUBSTRING(createtime, 9, 2) <= 21 THEN 'thirdWeek'ELSE 'fourWeek' END as `week`, count(ID) numFROM `robot` GROUP BY CASE WHEN SUBSTRING(createtime, 9, 2) <= 7 THEN 'firstWeek'WHEN SUBSTRING(createtime, 9, 2) <= 14 THEN 'secondWeek'WHEN SUBSTRING(createtime, 9, 2) <= 21 THEN 'thirdWeek'ELSE 'fourWeek' END

行转列

select
MAX(case when `week` = 'firstWeek' then num else 0 end) firstWeek,
MAX(case when `week` = 'secondWeek' then num else 0 end) secondWeek,
MAX(case when `week` = 'thirdWeek' then num else 0 end) thirdWeek,
MAX(case when `week` = 'fourWeek' then num else 0 end) fourWeek
from (SELECT CASE WHEN SUBSTRING(createtime, 9, 2) <= 7 THEN 'firstWeek'WHEN SUBSTRING(createtime, 9, 2) <= 14 THEN 'secondWeek'WHEN SUBSTRING(createtime, 9, 2) <= 21 THEN 'thirdWeek'ELSE 'fourWeek' END as `week`, count(ID) numFROM `robot` GROUP BY CASE WHEN SUBSTRING(createtime, 9, 2) <= 7 THEN 'firstWeek'WHEN SUBSTRING(createtime, 9, 2) <= 14 THEN 'secondWeek'WHEN SUBSTRING(createtime, 9, 2) <= 21 THEN 'thirdWeek'ELSE 'fourWeek' END
) t

本年

将上面的sql用下面 where 后面的过滤一下即可

SELECT *
FROM robot
WHERE YEAR(createtime) = YEAR(CURDATE());	

返回列表