MySql 行转列的玩法 ,实战案例教学(MAX函数的坑简析)

前言

既然有人问到mysql的行专列,那么就一块来玩一玩。

 

正文

先准备个样例数据:
 

 环境气候表 (假装是一张用于接收某个检测数据每天上报过来的环境数据)

建表SQL:
 

CREATE TABLE `env_climate` (
    `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `area` VARCHAR(50) NULL DEFAULT NULL COMMENT '地区' COLLATE 'utf8_general_ci',
    `item_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '参数项名' COLLATE 'utf8_general_ci',
    `item_value` VARCHAR(50) NULL DEFAULT NULL COMMENT '参数项值' COLLATE 'utf8_general_ci',
    `date` VARCHAR(50) NULL DEFAULT NULL COMMENT '日期' COLLATE 'utf8_general_ci',
    PRIMARY KEY (`id`) USING BTREE
)
COMMENT='环境气候表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;

然后填充一些数据:

INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (1, '深圳', '温度', '12', '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (2, '深圳', '湿度', NULL, '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (3, '深圳', '光照', '1300', '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (4, '成都', '温度', '45', '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (5, '成都', '湿度', '32', '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (6, '成都', '光照', '1300', '2022-11-01');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (7, '成都', '湿度', '32', '2022-11-02');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (8, '成都', '温度', '26', '2022-11-02');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (9, '成都', '光照', '230', '2022-11-02');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (10, '深圳', '温度', '26', '2022-11-02');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (11, '深圳', '湿度', '34', '2022-11-02');
INSERT INTO `env_climate` (`id`, `area`, `item_name`, `item_value`, `date`) VALUES (12, '深圳', '光照', '5000', '2022-11-02');

看一下示例数据情况:
 

 

 

行转列的结果:

可以看到,本来温度、地区 、数值 都是一行行的数据 ,我们转列之后,以日期&地区的维度,直观看到了 属于这个地区的 温度、湿度、光照 等数据。

怎么玩的呢?

接下来看SQL,介绍 3种小玩法。

第一种  用MAX + GROUP  实现  (有坑,文末会讲)

SELECT DATE AS '日期', AREA, 
MAX(CASE WHEN item_name='温度' THEN item_value ELSE '--'END) AS "温度",
MAX(CASE WHEN item_name='湿度' THEN item_value ELSE '--'END) AS "湿度", 
MAX(CASE WHEN item_name='光照' THEN item_value ELSE '--'END) AS "光照"
FROM env_climate
GROUP BY AREA, DATE 

效果:

 

 

第二种 使用SUM +GROUP BY  实现

SELECT DATE AS '日期', AREA AS '地区', 
SUM(CASE WHEN item_name='温度' THEN item_value ELSE '--'END) AS "温度",
SUM(CASE WHEN item_name='湿度' THEN item_value ELSE '--'END) AS "湿度", 
SUM(CASE WHEN item_name='光照' THEN item_value ELSE '--'END) AS "光照"
FROM env_climate
GROUP BY AREA, DATE 

效果:

ps:因为SUM是累计,所以只针对数字做了计算,可以看到我们value值尽管是字符串类型,mysql在做计算还是很友好过滤掉了非数字的值,所以计算完后返回的值,变成蓝色,代表是数字

 

第三种 使用 GROUP_CONCAT +GROUP BY  实现

SELECT DATE AS '日期', AREA, 
    group_concat(CASE WHEN item_name = '温度' THEN item_value END SEPARATOR '') '温度',
    group_concat(CASE WHEN item_name = '湿度' THEN item_value END SEPARATOR '') '湿度',
    group_concat(CASE WHEN item_name = '光照' THEN item_value END SEPARATOR '') '光照'
FROM env_climate
GROUP BY DATE,AREA;

效果:
 

 

!!!!!注意点 

我们把NULL 情况 赋值 ‘ 无’  Max 的劣质行为就暴露了:

MAX(CASE WHEN item_name='湿度' THEN item_value ELSE '无'END) AS "湿度"

 

 

为什么会这样呢?

 其实如果有经验的SQL人,都知道MAX 的玩法是有坑的,它只保证了 被MAX 的这个值的最大值。

然后如果你是字符串去MAX, 那么 mysql就会去比较这个值的 从左到右的一个个字符去做比较。 

这么说可能还是有人不清楚。

 立马做几个小例子,来讲这些坑暴露出来给大知道。

坑一 针对 varchar 做 max 、order排序

搞个新表,age字段故意搞成 字符串 varchar 类型 

好玩的来咯:
 

可以看到针对varchar 类型 ,去做 max ,显然是跟我们想象不一样的。

 稀缺手绘真迹解释:

 

其实这仅仅是一个针对varchar 使用max的 一个坑。 

那么其实使用max 和 group by ,还有坑没?  有。

坑二 ,max和group 多字段 乱数据

表数据:

 我们  想根据SID 分组 找出 score最大的 行值 ,然后展示当前行的 sid 、score、 cid :

错误踩坑:
 


SELECT sid,cid,MAX(score) as score
FROM stu_score
GROUP BY sid;

 

 

 

 

因为用max 配和 group的时候, mysql是个脑子转的很快但是想东西很简单的小孩,他只管把max的这个字段超出最大值,然后其他字段都是 图快,先拿到符合条件 sid = 1001的那行,就把相关其他字段都直接赋值了。 所以 第一个sid=1001 的 那行,cid是101, 赋值。

所以出来了

 

不好意思,这篇是讲行转列,不小心跑题了。 那就先到这里吧。

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小目标青年

对你有帮助的话,谢谢你的打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值