标题mysql distinct 和 group by 去重
一、先说结论:
MySQL中常用去重复数据的方法是使用 distinct 或者 group by
group by 分组后,如果没有对分组后的数据进行操作,如使用聚合函数/分组函数:count、sum、avg、max 、min,分组后直接显示该分组的第一条数据。
二、接下来看示例:
说明:
有一个事件评论表,针对每个事件,用户都可以发表评论,每发表一次评论,会生成一条记录
需求:
查询出每个事件中的最新评论
Sql脚本:
DROP TABLE IF EXISTS t1;
CREATE TABLE t1
(
event_id VARCHAR(32) NOT NULL COMMENT '事件id',
save_id VARCHAR(32) NOT NULL COMMENT '评论编号(评论一次生成一个)',
remark VARCHAR(512) COMMENT '评论',
created_by VARCHAR(32) COMMENT '创建者',
created_at DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (event_id, save_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT = '事件评论表';
insert into t1(event_id,save_id,remark,created_by,created_at) values
('33382DC38943452787801511501F82','ACAC06C970484598BEC213552CC2445C','666','Ken','2023-01-01 09:52:03')
, ('33382DC38943452787801511501F82','DDAFBB48ECBA4BC5B8DD560F97E813DD','牛','Bebe','2023-01-02 13:36:25')
, ('3C9E84678DA84DFDA3AA0F4669E7DFA3','3F0921BC070F49D5801B169488113AEE','手动狗头-','Merry','2023-02-05 22:48:42')
, ('9612173DE985409D8CC7DEC9AE4D925','141CC3D1F95B47BA9D5DAAEDB66CA4BE','已阅','Nancy','2023-03-07 08:01:01')
, ('9612173DE985409D8CC7DEC9AE4D925','4747F063294447B6A469D4ED272AF1KL','已阅+1','Bebe','2023-03-08 10:32:30')
, ('9612173DE985409D8CC7DEC9AE4D925','82F18CCDDB194BA18D3911C387D4B326','已阅+2','Alan','2023-03-08 10:32:30');
步骤:
1、查询出每个事件的最大创建时间(最新记录)
SELECT event_id, MAX(created_at) AS created_at
FROM t1
GROUP BY event_id;
2、内联查询,查询出其他数据
SELECT
DATA.*
FROM (
SELECT event_id, MAX(created_at) AS created_at
FROM t1
GROUP BY event_id
) LATEST
INNER JOIN (
SELECT *
FROM t1
) DATA
ON LATEST.event_id = DATA.event_id AND LATEST.created_at = DATA.created_at;
发现问题:
看起来似乎没有问题,但是发现却查出了4条记录,
虽然在上一步中,取MAX(created_at) 只有3条记录,但这里进行内联查询时会有4条记录
因为最后2个评论的创建时间是相同的,
如果说只取每个事件中的最新评论,其实这2条数据任一即可,因此需要去重!
解决问题:
在语句最后面加上 GROUP BY 进行去重
最终sql:
SELECT
DATA.*
FROM (
SELECT event_id, MAX(created_at) AS created_at
FROM t1
GROUP BY event_id
) LATEST
INNER JOIN (
SELECT *
FROM t1
) DATA
ON LATEST.event_id = DATA.event_id AND LATEST.created_at = DATA.created_at
-- 去重
GROUP BY DATA.event_id, DATA.created_at;