使用多个选择器从 SQL 中的一组中选择一行
Selecting one row from a group in SQL with multiple selectors
(此问题特定于 MySQL 5.6,不包括 CTE)
假设我有一个这样的 table(实际的 table 是由具有多个连接的子查询构成的,并且相当复杂):
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
的双重分组),然后 select 每组中的一行,更喜欢行最高 ACCESS_LEVEL
,并在具有相同访问权限的行中,选择深度最低的行。没有两行会具有相同的 (ID, DEPTH)
,因此我们无需担心超出这一点的问题。
例如上面的table,我们select:
ID NAME POWER ACCESS_LEVEL DEPTH
1 Isis song 2 1
2 Zeus storms 2 2
这些团体是(Odin、Isis)和(Enki、Thor、Zeus)。在第一组中,我们更喜欢 Odin 而不是 Isis,因为 Odin 具有更高的 ACCESS_LEVEL
。在第二组中,我们选择 Zeus,因为 Zeus 和 Thor 的 ACCESS_LEVEL
s 比 Enki 高,而在这两者之间,Zeus 的深度较低。
安大略省最坏的情况,我可以在应用程序级别执行此操作,但在数据库级别执行此操作允许使用 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 *
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 的解决方案可能会导致更好的查询计划。
您可能需要一些基于子查询
的分组 table
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
(此问题特定于 MySQL 5.6,不包括 CTE)
假设我有一个这样的 table(实际的 table 是由具有多个连接的子查询构成的,并且相当复杂):
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
的双重分组),然后 select 每组中的一行,更喜欢行最高 ACCESS_LEVEL
,并在具有相同访问权限的行中,选择深度最低的行。没有两行会具有相同的 (ID, DEPTH)
,因此我们无需担心超出这一点的问题。
例如上面的table,我们select:
ID NAME POWER ACCESS_LEVEL DEPTH
1 Isis song 2 1
2 Zeus storms 2 2
这些团体是(Odin、Isis)和(Enki、Thor、Zeus)。在第一组中,我们更喜欢 Odin 而不是 Isis,因为 Odin 具有更高的 ACCESS_LEVEL
。在第二组中,我们选择 Zeus,因为 Zeus 和 Thor 的 ACCESS_LEVEL
s 比 Enki 高,而在这两者之间,Zeus 的深度较低。
安大略省最坏的情况,我可以在应用程序级别执行此操作,但在数据库级别执行此操作允许使用 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 *
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 的解决方案可能会导致更好的查询计划。
您可能需要一些基于子查询
的分组 table 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