【问题标题】:get 1st and 2nd highest vlaue rows in case of similar values在相似值的情况下获得第 1 和第 2 高值行
【发布时间】:2018-04-08 02:50:23
【问题描述】:

我有一个包含以下列的表格:id、status、value。

id    status    value
--    ------    -----
1       10       100
2       10       100
3       10        60
4       11        20
5       11        15
6       12       100
7       12        50
8       12        50  

我想从每个状态组中获取第一和第二高值行的 id 和值。我的表应该有以下列:
状态,第一高的id,第一高的,第二高的id,第二高的。

我应该得到:

status  1stID  1stValue  2ndID  2ndValue
------  -----  --------  -----  --------
  10     1/2      100     2/1      100
  11      4       20       5       15
  12      6      100      7/8      50   

我尝试了各种解决方案,但我找不到相同值 1st s(具有相同值的两行,恰好是该状态组中的最高值)或相同值秒的解决方案。

例如,如果两行共享其状态组中的最高值,这个不太优雅的查询将返回两行具有相同状态、不同的第一个和相同的第二个:

    SELECT 2nds.status, 1sts.id AS "1stID",1sts.value AS "1stValue",
 2nds.id AS "2ndID",2nds.value AS "2ndValue" 
FROM    
    (SELECT v.* FROM 
    (SELECT status, MAX(value) AS "SecMaxValue" FROM table o
    WHERE value  < (SELECT MAX(value) FROM table 
                   WHERE status = o.status
                   GROUP BY status) AS m
    INNER JOIN table v
    ON v.status = m.status AND v.value = m.SecMaxValue) AS 2nds

    INNER JOIN

    (SELECT v.* FROM 
    (SELECT status, MAX(value) AS maxValue FROM table
    GROUP BY status) AS m
    INNER JOIN table v
    ON v.status = m.status AND v.value = m.MaxValue) AS 1sts    
    ON 1sts.status = 2nds.status ;

这个查询会给我:

status  1stID  1stValue  2ndID  2ndValue
------  -----  --------  -----  --------
  10      1      100       3       60
  10      2      100       3       60
  11      4       20       5       15
  12      6      100       7       50
  12      6      100       8       50     

最后,我想找到一个解决方案: 一种。如果有两行具有最高值,则查询将其中一个的详细信息放在第 1 列中,将其他的详细信息放在第 2 列中(不是哪个) 湾。如果有两行具有第二高值,则将最高值放在其位置,将秒数之一放在第二位置。

有没有办法改变上面的查询?有人有更好的解决方案吗?

  • 我遇到了几个第一个和第二个查询,但他们有同样的问题 - 例如这个解决方案:Finding the highest n values of each group in MySQL。它不会在同一行中提供第一名和第二名,但主要问题是它只提供了第一名。

谢谢

【问题讨论】:

  • 请以正确的格式提供样本数据、当前和期望的结果。这将非常有帮助。
  • 一旦人们升级到 MySQL 8.0,这种问题就会变得如此简单。只需使用RANK() window function
  • @BillKarwin 谢谢你的信息。我不知道 Mysql 中也引入了 rank()dense_rank()。是的,当然,这些功能将使这项任务变得比现在更简单。

标签: mysql max


【解决方案1】:

花了很多时间,终于找到了解决上述问题的方法。请尝试一下:

    select 1st.status as Status,
       SUBSTRING_INDEX(1st.id,'/',1) as 1stID,
       1st.value as 1stValue,
       (case when locate('/',1st.id) > 0 then SUBSTRING_INDEX(1st.id,'/',-1)
             else 2nd.id 
        end) as 2ndID,
        (case when locate('/',1st.id) > 0 then 1st.value
             else 2nd.value 
        end) as 2ndValue
        from
(
(select status, SUBSTRING_INDEX(Group_concat(id separator '/'),'/',2) as id,value
from t1
where (status,value) in (select status,value
from t1
group by status
having max(value))
group by status) 1st

inner join

(select status,id,value
from t1
where (status,value) not in (select status,value
from t1
group by status
having max(value))
group by status,value
order by status,value desc) 2nd
on 1st.status = 2nd.status)
group by 1st.status;

只需将 t1 替换为您的表名,它应该会像一个魅力一样工作。

Click here for Updated Demo

如果您有任何疑问,请随时提问。

希望对你有帮助!

【讨论】:

  • 谢谢哈希尔!演示中的查询与上面的查询不同。当您运行上面的查询时,由于某种原因,它会在第一行中放入 10 和预期的 1 和 2。演示中的查询实际上效果很好。对不起,也许我的问题不够清楚 - 我并不是说表格会在同一个单元格中同时显示第一个和第二个 id。我不是故意放一个字符串。我的意思是将 id 1 OR id 2. 放在右下角的单元格 id 6 或 id 7 中。我知道我可以将它从字符串中剪切并返回为整数,但这不会太复杂吗?再次感谢您的努力!
  • 好的。因此,您想将 1 或 2 显示为状态 10 的 1stID 和 2ndID?对吗?
  • 是的,如果您将 1 显示为第 1 位,则 2 将是第 2 位,反之亦然。哦,我注意到你在演示中添加了 10,我的错误,两者都很好用。在这种情况下,第一个 ID 可以是 1、2、10。第二个将是剩下的 2 个之一。
  • CONVERT(SUBSTRING_INDEX(1st.id,'/',1),UNSIGNED INTEGER) as 1stID 不起作用吗?
  • 工作。再次感谢!
猜你喜欢
  • 2019-09-12
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多