代码之家  ›  专栏  ›  技术社区  ›  Elon

在值相似的情况下,获得第一和第二高的vlaue行

  •  2
  • Elon  · 技术社区  · 8 年前

    我有一个包含以下列的表: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(具有相同值的两行,恰好是该状态组中的最高值)或相同值秒的解决方案。

    例如,如果两行共享其状态组中的最高值,那么这个不太优雅的查询将返回两个具有相同状态、不同1ST和相同2nd的行:

        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     
    

    最后,我想找到一个解决方案,其中: a、 如果有两行的值最高,则查询会将其中一行的详细信息放在第1列中,另一行的详细信息放在第2列中(没有数学) b、 如果有两行具有第二高的值,则将最高值放在其位置,其中一秒放在第二位。

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

    谢谢

    1 回复  |  直到 8 年前
        1
  •  2
  •   Harshil Doshi    8 年前

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

        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

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

    希望有帮助!