greatest-n-per-group
有超过 1800 个带标签的问题和一些出色的答案,我想我会找到这个问题的解决方案 - 但我要么错过了解决方案,要么我需要一种新方法。
我有一个表 photo_types
来存储 user
的投票,他们正在投票(赞成或反对)他们认为给定的特定 photo_type
照片是。照片类型为 1-10
,每次投票将为 1
或 -1
。
+----+-----+-----------+------------+------+
| id | user | photo_id | photo_type | vote |
+----+------+----------+------------+------+
| 1 | jane | photo1 | 1 | 1 |
| 2 | jane | photo2 | 2 | 1 |
| 3 | jane | photo3 | 4 | -1 |
| 4 | ben | photo1 | 1 | 1 |
| 5 | ben | photo2 | 3 | -1 |
| 6 | ben | photo2 | 2 | 1 |
| 7 | mary | photo1 | 1 | -1 |
| 8 | mary | photo3 | 10 | 1 |
| 9 | mary | photo2 | 1 | 1 |
| 10 | mary | photo1 | 2 | -1 |
+----+------+----------+------------+------+
我需要将此表左连接回 photos
表(其中包含给定照片的所有其他详细信息)- 但仅包括前 2 个投票类型 每张照片。
我需要LEFT JOIN
photo_types
表的photos
表如下所示:
+----+----------+------------+----------------+---------------+------------+
| id | photo_id | photo_name | photographer | location | date |
+----+----------+------------+----------------+---------------+------------+
| 1 | photo1 | the bridge | Bill Murray | Brooklyn, NY | 2012-10-11 |
| 2 | photo2 | the cat | Jacques Chirac | Paris, France | 2013-01-03 |
| 3 | photo3 | a car | the Grinch | London, UK | 2016-09-01 |
+----+----------+------------+----------------+---------------+------------+
我显然是通过 photo_id
连接两个表。
为了获得每张照片的最高投票类型,我尝试了这样的子查询:
SELECT photo_id, photo_type, sum(vote) AS votes
FROM photo_types
GROUP BY photo_type, photo_id
HAVING votes>0
ORDER BY votes DESC
按 photo_type
和 photo_id
对投票总和进行分组。
这工作正常,但包括所有具有 sum(vote) > 0
的类型 - 而不仅仅是前 2 个投票类型。
SQL Fiddle here
当包含在联接中时,它看起来像:
SELECT *
FROM photos
LEFT JOIN
(SELECT photo_id, photo_type, sum(vote) AS votes
FROM photo_types
GROUP BY photo_type, photo_id
HAVING votes>0
ORDER BY votes DESC) AS pt
ON photos.photo_id = pt.photo_id
WHERE photos.date > '2010-01-01';
我曾希望使用 Bill Karwin's solution但我无法根据分组值(在我的例子中是 SUM
)将表连接到自身。我试过的子查询看起来像:
SELECT pt1.*, SUM(pt1.vote) AS votes1, SUM(pt2.vote) AS votes2
FROM photo_types AS pt1
LEFT OUTER JOIN photo_types AS pt2
ON pt1.photo_id = pt2.photo_id
AND (votes1 < votes2
OR (votes1 = votes2 AND pt1.id < pt2.id))
WHERE pt2.photo_id IS NULL
...这不起作用,因为它试图根据计算值连接两个表(与 Bill 的解决方案不同)。
SQL Fiddle here
问题
当分组基于诸如 SUM(xxx)
之类的计算值时,是否有办法获得 greatest-n-per-group
?
部分解决这个问题的解决方案是 here和 here但不要在分组值中包含聚合。
另一种明显的方法是在每次投票时重新计算最高投票值,并将其直接存储在 photos
表中 - as discussed here - 但除非不可能 - 出于各种原因,我更愿意在 SELECT
中进行计算。
最佳答案
如果列表有限,最简单的方法是 substring_index()
/group_concat()
技巧:
SELECT photo_id,
SUBSTRING_INDEX(GROUP_CONCAT(photo_type ORDER BY votes DESC), ',', 2) as top2
FROM (SELECT photo_id, photo_type, sum(vote) AS votes
FROM photo_types
GROUP BY photo_type, photo_id
HAVING votes > 0
) pt
GROUP BY photo_id;
注意事项:
group_concat()
的中间字符串大约为 1k —— 这对于这个问题来说绰绰有余。- 备选方案(如您所见)要么使用变量进行更复杂的查询。
关于mysql - 在子查询中加入 `greatest-n-per-group` 和 SUM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41475437/