【问题标题】:How to select the lowest value from selection如何从选择中选择最小值
【发布时间】:2023-03-11 15:00:02
【问题描述】:

我使用的是 MySQL 5.1

表用户:

id | exp
---------
5  | 5
4  | 9

表层数:

id|min_exp
----------
1 | 0
2 | 5
3 | 8

如何通过levels.id选择用户?

我需要加入表用户和级别。 这必须是有效的:

users.exp >= levels.min_exp

并且 min_exp 应该尽可能低。

预期输出:

users.id|users.exp|levels.id|levels.min_exp
   5    |    5    |    2    |      5
   4    |    9    |    3    |      8                             

【问题讨论】:

  • 我不太清楚你在问什么。您能否编辑您的问题并提供您期望的输出示例?
  • 你的用户表中有level_id吗?
  • 提供有关这些表应连接哪些列的信息,因为levels 表中没有可用于与users 连接的列。

标签: mysql database select


【解决方案1】:

如果 level.id 没有差距,您可以通过加入 levels 两次并避免聚合来获得更好的性能:

select users.id, users.exp, current_level.id, current_level.min_exp
from levels current_level
join levels next_level on next_level.id = current_level.id + 1
join users on users.exp >= current_level.min_exp
    and users.exp < next_level.min_exp

如果您经常需要最小/最大体验括号,我建议您将current_level/next_level 加入一个视图。

编辑:我刚刚想到最高级别的用户会失败。根据您要如何处理(用户停止获得最大 XP 还是继续获得它而不增加级别?),您可以在 levels 中添加高于最大级别的虚拟记录或使 next_level 加入外部连接。

【讨论】:

  • 此版本存在严重的性能问题。它必须匹配两个表中的所有行。过滤它以仅返回单个用户的级别仍然必须匹配级别表中的所有行。
  • @TupshinHarper:从预期的输出来看,查询应该获得所有用户的级别。我承认使用 order by / limit 1 或聚合在查询单个用户时性能更好,但不适用于查询所有用户。为了对所有用户进行分组和聚合,DBMS 将使用U * (1/2) L 构建一个中间记录集,其中 U 是用户中的记录数,L 是级别中的记录数(假设用户按级别均匀分布)。 level 上的自连接允许优化器使用 2 个大小为 U 和 L 的记录集来构建结果。
  • 很公平。您的答案非常适合返回所有用户的级别,这确实看起来像他们所要求的。对于返回特定用户级别的特殊情况,我仍然会推荐下面的版本。
【解决方案2】:

您想要用户可以看到的最低级别:

select
    u.id as UserId,
    MIN(l.id) as LevelId
from
    Users u
    inner join Levels l on
        u.exp >= l.min_exp
group by
    u.Id

如果您只想为特定用户使用它:

select
    u.id as UserId,
    MIN(l.id) as LevelId
from
    Users u
    inner join Levels l on
        u.exp >= l.min_exp
where
    u.id = 5
group by
    u.Id

【讨论】:

  • 我相信您想要用户体验超过其“exp”要求的最低级别,而不是最高级别。
  • Eric,我相信他想要最低的体验级别(即用户的当前级别)。 max(l.id) 应该是 min(l.id)
【解决方案3】:

这个问题措辞不清楚,但从上下文来看,您似乎正在寻找一个人在当前 exp 和 min_exp 下达到的最高水平。

既然你知道你要找的用户的id,就可以查询

select users.id as uid,users.exp,levels.id as levelid from users,levels where users.id = 4 and levels.min_exp <= users.exp order by levelid desc limit 1

如果您确保两个表上都有正确的索引

alter table users add primary key (id)
alter table levels add primary key (id)
alter table levels add unique key(min_exp);

(非主键索引也可以) 那么查询效率极高:

explain select users.id as uid,users.exp,levels.id as levelid from users,levels where users.id = {{uid}} and levels.min_exp <= users.exp order by levelid desc limit 1;
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | users  | const | PRIMARY       | PRIMARY | 4       | const |    1 |                 |
|  1 | SIMPLE      | levels | index | min_exp       | PRIMARY | 4       | NULL  |    1 |     Using where |
----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+`

【讨论】:

  • 我还不能对其他回复发表评论,但目前的主要答案与 用户表的大小和级别表的大小成正比。如果您将其修改为仅返回单个用户的级别(users.id),那么它仍然与级别表的大小成正比(对其运行解释)。
猜你喜欢
  • 1970-01-01
  • 2013-04-03
  • 2013-12-30
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2011-07-25
  • 2011-12-14
  • 2021-05-06
相关资源
最近更新 更多