【问题标题】:Selecting one row from a group in SQL with multiple selectors使用多个选择器从 SQL 中的组中选择一行
【发布时间】:2017-11-05 19:24:19
【问题描述】:

(这个问题是 MySQL 5.6 特有的,不包括 CTE)

假设我有一个这样的表(实际的表是由具有多个连接的子查询组成的,并且稍微复杂一些):

ID  NAME    POWER    ACCESS_LEVEL  DEPTH
1   Odin    poetry   1             0
1   Isis    song     2             1
2   Enki    water    1             0
2   Zeus    storms   2             2
2   Thor    hammer   2             3

我想先按ID 对它们进行分组(如果重要的话,实际上是按PRINCIPAL_TYPE, PRINCIPAL_ID 进行的双重分组),然后从每个组中选择一行,首选ACCESS_LEVEL 最高的行,然后在行中使用相同的访问,选择深度最低的访问。没有两行会有相同的(ID, DEPTH),所以我们不必担心超出这一点。

以上表为例,我们选择:

ID  NAME    POWER    ACCESS_LEVEL  DEPTH
1   Isis    song     2             1
2   Zeus    storms   2             2

这些组是(奥丁,伊希斯)和(恩基,雷神,宙斯)。在第一组中,我们更喜欢 Odin 而不是 Isis,因为 Odin 的 ACCESS_LEVEL 更高。在第二组中,我们选择 Zeus,因为 Zeus 和 Thor 的 ACCESS_LEVELs 比 Enki 高,而在这两者之间,Zeus 的深度较低。

安大略省最糟糕的情况,我可以在应用程序级别执行此操作,但在数据库级别执行此操作允许使用 LIMITSORT BY 进行分页,而不是获取整个结果集。

【问题讨论】:

    标签: mysql sql group-by grouping mysql-5.6


    【解决方案1】:

    这是一种使用相关子查询的方法:

    select t.*
    from t
    where (access_level, depth) = (select access_level, depth
                                   from t t2
                                   where t2.id = t.id
                                   order by access_level desc, depth asc
                                   limit 1
                                  );
    

    【讨论】:

      【解决方案2】:

      你可能需要一些基于子查询的分组表

        select * 
        my_table m2
        inner join (
        select id, t.level, min(depth) depth 
        from my_table m
        inner join  (
         select id, max(ACCESS_LEVEL)  level 
         from  my_table
         group by id ) t on t.id= m.id and t.level = m.access_level
        group by id level ) t2 on t2.id = m2.id 
              and t2.depth = m2.depth and t2.level = m2.access_level
      

      【讨论】:

        【解决方案3】:

        这可能有效。

        select *
        from your_table t1
        where (t1.access_level, t1.depth) = (
           select t2.access_level, min(t2.depth)
           from your_table t2
           where (t2.access_level, t2.id) = (
              select max(t3.access_level), t3.id
              from your_table t3
              where t3.id = t1.id
           )
        )
        

        但是,我觉得 Gordon 的解决方案可能会带来更好的查询计划。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-20
          • 2011-11-12
          • 2019-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多