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

Mysql 在SQL中使用多个选择器从组中选择一行,mysql,sql,group-by,grouping,mysql-5.6,Mysql,Sql,Group By,Grouping,Mysql 5.6,(这个问题是针对MySQL 5.6的,它不包括CTE) 假设我有一个这样的表(实际的表是由一个包含多个联接的子查询组成的,并且比较复杂): 我想首先按ID对它们进行分组(实际上是按PRINCIPAL\u TYPE,PRINCIPAL\u ID进行双重分组,如果这很重要的话),然后从每组中选择一行,优先选择访问级别最高的行,并在具有相同访问权限的行中选择深度最低的行。没有两行具有相同的(ID,DEPTH),因此我们不需要担心超出这一点 例如,在上表中,我们选择: ID NAME POWER

(这个问题是针对MySQL 5.6的,它不包括CTE)

假设我有一个这样的表(实际的表是由一个包含多个联接的子查询组成的,并且比较复杂):

我想首先按
ID
对它们进行分组(实际上是按
PRINCIPAL\u TYPE,PRINCIPAL\u ID
进行双重分组,如果这很重要的话),然后从每组中选择一行,优先选择访问级别最高的行,并在具有相同访问权限的行中选择深度最低的行。没有两行具有相同的
(ID,DEPTH)
,因此我们不需要担心超出这一点

例如,在上表中,我们选择:

ID  NAME    POWER    ACCESS_LEVEL  DEPTH
1   Isis    song     2             1
2   Zeus    storms   2             2
这些群体是(奥丁、伊西斯)和(恩基、托尔、宙斯)。在第一组中,我们更喜欢Odin而不是Isis,因为Odin的访问级别更高。在第二组中,我们选择了宙斯,因为宙斯和托尔的
ACCESS\u级别高于恩基,而在这两者之间,宙斯的深度较低


在最坏的情况下,我可以在应用程序级别执行此操作,但在数据库级别执行此操作允许使用
LIMIT
SORT BY
进行分页,而不是获取整个结果集。

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

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

下面是一个使用相关子查询的方法:

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
                              );
这可能行得通

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

这可能会奏效

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

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

  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

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

  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