使用多个选择器从SQL中的组中选择一行

时间:2017-11-05 19:24:20

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

(此问题特定于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的双重分组),然后从每个组中选择一行,优先选择{{1在具有相同访问权限的行中,选择具有最低深度的行。没有两行具有相同的ACCESS_LEVEL,因此我们不必担心超出这一点。

例如,使用上表,我们选择:

(ID, DEPTH)

这些团体是(Odin,Isis)和(Enki,Thor,Zeus)。在第一组中,我们更喜欢Odin而不是Isis,因为Odin有更高的ID NAME POWER ACCESS_LEVEL DEPTH 1 Isis song 2 1 2 Zeus storms 2 2 。在第二组中,我们采用宙斯,因为宙斯和托尔比恩基更高ACCESS_LEVEL,而在这两者之间,宙斯的深度更低。

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

3 个答案:

答案 0 :(得分:2)

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

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
                              );

答案 1 :(得分:1)

这可能有效。

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的解决方案可能会带来更好的查询计划。

答案 2 :(得分:1)

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

  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