提问人:William Lightning 提问时间:10/27/2023 更新时间:10/27/2023 访问量:107
返回包含某一列的按组最大值的返回行,说明列中的重复值
Return row holding the group-wise maximum of a certain column, account for duplicate values in column
问:
我一直在尝试报告活动门户的观众统计数据。我注意到在很多情况下,人们会多次重新联系,所以我想出了一个viewer_id将它们联系在一起。每次他们开始观看活动时,他们都会输入一个姓名和观看人数(包括他们自己)。
我希望能够选择按event_id和viewer_id组合分组的事件视图,同时为该给定组合选择viewer_count最大的行。
示例架构和数据
-- Server Version: MySQL 8.0.43
CREATE TABLE `event_viewers` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`event_id` bigint unsigned NOT NULL,
`viewer_id` bigint unsigned NOT NULL,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`viewer_count` int NOT NULL,
PRIMARY KEY (`id`)
);
-- Event ID 1
insert into event_viewers (id, event_id, viewer_id, name, viewer_count)
values (1, 1, 1, 'Bert Kuvalis0', 1),
(6, 1, 2, 'Wanda Steuber0', 7),
(11, 1, 3, 'Erick Nienow0', 4),
(16, 1, 3, 'Erick Nienow1', 3),
(17, 1, 3, 'Erick Nienow2', 4);
-- Event ID 2
insert into event_viewers (id, event_id, viewer_id, name, viewer_count)
values (2, 2, 1, 'Bert Kuvalis2', 11),
(7, 2, 2, 'Wanda Steuber2', 10),
(12, 2, 3, 'Erick Nienow3', 7),
(18, 2, 2, 'Wanda Steuber3', 13);
我希望能够得到以下结果:
编号 | event_id | viewer_id | 名字 | viewer_count |
---|---|---|---|---|
1 | 1 | 1 | 伯特·库瓦利斯 | 1 |
6 | 1 | 2 | 万达·斯图伯0 | 7 |
11 | 1 | 3 | 埃里克·尼诺0 | 4 |
2 | 2 | 1 | 伯特·库瓦利斯2 | 11 |
18 | 2 | 2 | 万达·斯图伯3 | 13 |
12 | 2 | 3 | 埃里克·尼诺3 | 7 |
在上面的结果中,有一条具有相同event_id的记录,viewer_id & viewer_count 具有最大的viewer_count,我通过选择匹配的第一行 (id 11) 来解决这个问题,丢弃第二行 (id 17)。对于我的问题,我实际上并不关心哪个被选中(11 或 17),只要只有一个被选中。
我尝试过的事情:
分组依据
我最成功的尝试是使用 GROUP BY 和 MAX,但缺少基本行 id 和 name。
SELECT
ev.event_id,
ev.viewer_id,
MAX(ev.`viewer_count`) AS `viewer_count`
FROM event_viewers as ev
GROUP BY ev.viewer_id, ev.event_id ORDER BY `event_id`, `viewer_id`;
这将返回所需的输出,但不包括 id 和 name 列。
event_id | viewer_id | viewer_count |
---|---|---|
1 | 1 | 1 |
1 | 2 | 7 |
1 | 3 | 4 |
2 | 1 | 11 |
2 | 2 | 13 |
2 | 3 | 7 |
不存在的地方
我尝试使用WHERE NOT EXISTED,看看我是否可以排除重复项,更喜欢最大的。
SELECT DISTINCT ev1.* from event_viewers ev1
WHERE NOT EXISTS (
SELECT * FROM event_viewers as ev2
WHERE ev2.viewer_id = ev1.viewer_id
AND ev2.event_id = ev1.event_id
AND ev2.viewer_count > ev1.viewer_count
) ORDER BY `event_id`, `viewer_id`;
结果见下文,因为 WHERE NOT EXISTS、LEFT JOIN 和 WITH WINDOW 尝试都具有相同的输出。它们包括一个额外的行,该行具有匹配的event_id、viewer_id和viewer_count它出现两次。(11 和 17 都显示,只想要其中一个)。
左加入
根据MySQL文档中关于保存特定列的按组最大值的行的建议,我尝试使用LEFT JOIN:
SELECT ev1.* FROM event_viewers ev1
LEFT JOIN event_viewers ev2
ON ( ev1.viewer_count<ev2.viewer_count AND ev1.viewer_id=ev2.viewer_id AND ev1.event_id=ev2.event_id )
WHERE ev2.id IS null
ORDER BY ev1.event_id, ev1.`viewer_id`;
结果见下文,因为 WHERE NOT EXISTS、LEFT JOIN 和 WITH WINDOW 尝试都具有相同的输出。它们包括一个额外的行,该行具有匹配的event_id、viewer_id和viewer_count它出现两次。(11 和 17 都显示,只想要其中一个)。
带窗户
根据MySQL文档中关于保存特定列的按组最大值的行的建议,我尝试使用WITH:
WITH w1 AS (
SELECT *,
RANK() OVER (PARTITION BY viewer_id, event_id
ORDER BY viewer_count DESC
) AS `Rank`
FROM event_viewers
)
SELECT id, event_id, viewer_id, name, viewer_count
FROM w1
WHERE `Rank` = 1
ORDER BY `event_id`, `viewer_id`;
结果见下文,因为 WHERE NOT EXISTS、LEFT JOIN 和 WITH WINDOW 尝试都具有相同的输出。它们包括一个额外的行,该行具有匹配的event_id、viewer_id和viewer_count它出现两次。(11 和 17 都显示,只想要其中一个)。
编号 | event_id | viewer_id | 名字 | viewer_count |
---|---|---|---|---|
1 | 1 | 1 | 伯特·库瓦利斯 | 1 |
6 | 1 | 2 | 万达·斯图伯0 | 7 |
11 | 1 | 3 | 埃里克·尼诺0 | 4 |
17 | 1 | 3 | 埃里克·尼诺2 | 4 |
2 | 2 | 1 | 伯特·库瓦利斯2 | 11 |
18 | 2 | 2 | 万达·斯图伯3 | 13 |
12 | 2 | 3 | 埃里克·尼诺3 | 7 |
答:
您需要一些独特的列来打破联系,因此您可以消除 viewer_count=4 的冗余行。
下面是一个示例,我在窗口中添加了一个函数,然后使用 ROW_NUMBER() 而不是 RANK():ORDER BY ... id ASC
WITH w1 AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY viewer_id, event_id
ORDER BY viewer_count DESC,
id ASC -- here
) AS ROWNUM
FROM event_viewers
)
SELECT id, event_id, viewer_id, name, viewer_count
FROM w1
WHERE ROWNUM = 1
ORDER BY `event_id`, `viewer_id`;
评论
下一个:替换嵌套查询以获取最新的相关行
评论