mysql - 在 MySql (8.0.13) 中查找 max 和 second max 之间的差异,按列分组,而不使用 order by 和 limit 子句
问题描述
我有一个包含 ID、ad_id、amount_time 列的表,其中显示了用户的 ID、他们看到的广告以及他们看到的时间。以下是数据示例:
table name: ads
ID | ad_id | amount_time
1 2 600
1 3 300
3 1 400
1 3 100
1 1 700
我们希望结果显示 amount_time 的 max 和 2nd max 之间的差异,按 ID 和 ad_id 分组
所以结果是
ID |ad_id | diff_amount_time
1 3 200
我可以通过执行获得总表的 max 和 second_max:
select
(SELECT MAX(amount_time) FROM ads) maxtime,
(SELECT MAX(amount_time) FROM ads
WHERE amount_time NOT IN (SELECT MAX(amount_time) FROM ads )) as
second_max_time
但是,我无法合并 group by 子句以获得我的结果。我知道有一种方法可以合并order by
并limit 2
获得最大值和第二个最大值,但这在计算上很昂贵,并且想知道是否有另一种解决方案而无需订购 amount_time 列。
解决方案
在 MySQL 8.0.2+ 中,最简单且可能最高效的方法是使用Window Functions。
我们将使用Row_Number()
函数,它将确定ID
和组合内的行号值ad_id
。行号将基于降序amount_time
值。因此,最高amount_time
值的行号为 1,第二高的行号为 2。
现在,我们将此结果集用作派生表,并在和上聚合 ( GROUP BY
) 。我们可以使用条件表达式来确定每个组中最高值和第二高值之间的差异。ID
ad_id
CASE .. WHEN
SELECT
dt.ID,
dt.ad_id,
(MAX(CASE WHEN dt.row_no = 1 THEN dt.amount_time END) -
MAX(CASE WHEN dt.row_no = 2 THEN dt.amount_time END)) AS diff_amount_time
FROM
(
SELECT
ID,
ad_id,
amount_time,
ROW_NUMBER() OVER (PARTITION BY CONCAT(ID, '-', ad_id)
ORDER BY amount_desc) AS row_no
FROM ads
) AS dt
GROUP BY dt.ID, dt.ad_id
-- to remove cases where there is no second highest
-- when there is no second highest amount, then the difference will be null
-- because 5 - null = null
HAVING diff_amount_time IS NOT NULL
推荐阅读
- java - 一个线程无法更改另一个线程的变量,即使使变量变为 volatile
- jquery - 如何重新初始化推送通道监听
- amazon-web-services - 将索引转换为排序键 Redshift
- scala - 如何强制案例类构造函数在 Scala 中具有预定义的签名?
- python - 如何在不同的函数中引用对象?
- azure - 为什么 Azure Cosmos 查询在指定分区键时具有更高的 RU?
- java - 如何将 [A,B,C] 之类的字符串拆分为 ABC (Java)
- apache-spark - 考拉 sort_index 增加 spark 分区
- react-native - react-native-google-places-autocomplete 在用视图包装时不起作用
- python - 从 Pandas 列中的行中删除特殊字符的大多数 Pythonic 方法