返回包含特定列的分组最大值的行,考虑列中的重复值

问题描述 投票:0回答:1

我一直在尝试报告活动门户的观看者统计信息。我注意到很多情况下人们会多次重新连接,因此我制定了一个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);

我希望能够得到以下结果:

id 事件_id viewer_id 名字 观众人数
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 和名称。

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 列。

事件_id viewer_id 观众人数
1 1 1
1 2 7
1 3 4
2 1 11
2 2 13
2 3 7

不存在的地方

我尝试使用 WHERE NOT EXISTS 来查看是否可以排除重复项,更喜欢最大的。

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 都显示,只想要其中之一)。

id 事件_id viewer_id 名字 观众人数
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
sql mysql aggregate-functions greatest-n-per-group
1个回答
0
投票

您需要一些唯一的列来打破平局,因此您可以使用viewer_count = 4消除多余的行。

这是一个示例,我在窗口函数中添加了

ORDER BY ... id ASC
,然后使用 ROW_NUMBER() 而不是 RANK():

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`;
© www.soinside.com 2019 - 2024. All rights reserved.