MySQL:如何为基于范围而不是外键的关系编写查询?

标签 mysql

我在 MySQL 中有三个相关的表,但在技术上并未通过外键相互链接。它们是:用户级别类别

users 表有一个 karma 列,一个数字类型。根据这个业力数字,我想知道用户的级别,这是我从级别表中检索的。这不是一个硬性关系,因为一个级别与一个范围的业力值相关联,如下所示:

  • 1 级(最低业力:0)
  • 2 级(最低业力:100)
  • 3 级(最低业力:500)
  • ...

因此,如果用户的业力为 400,则返回值应为 2。为了使事情稍微复杂一些,级别编号表示用户的类别,其定义存储在类(class)表。这又是一个范围关系:

  • Ant 等级(最低等级 1)
  • 猫头鹰等级(最低等级 5)
  • 狮子级(最低等级 100)
  • ...

总之,我们讨论的是基于范围值而彼此具有隐式关系的三个表。我的问题涉及如何有效地查询这些表。我的一个非常常见的需求是根据条件获取一个或多个用户的信息,结果集应该包含用户详细信息,而且还包含用户的级别和类别。

对于单个用户,我设法编写了这个运行良好的查询:

SELECT u.*,  lv.num as level, lvc.title as class, lvc.id as classid
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = ? AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1;

但是,如果我通过保留 WHERE u.id = 来扩大结果集?并删除 LIMIT 1,从而查询用户列表,我得到了所有三个表的组合。通常,您可以通过对键进行内部联接来降低行数,但由于这是范围检查, 那行不通。我尝试在内连接条件中使用范围检查,但这会带来相同的结果。即使使用分组我也无法得到我想要的结果。

在绝望的尝试中,我想出了这个查询,它有效:

SELECT usr.*, 
(SELECT lv.num as level
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as level,
(SELECT lvc.title as class
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as class,
(SELECT lvc.image as class_image
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as class_image,
(SELECT lvc.id as classid
FROM user as u, level as lv, levelclass as lvc
WHERE u.id = usr.id AND lv.min_karma <= u.karma AND lv.num <= lvc.minlevel_num
ORDER BY lv.num DESC LIMIT 1) as classid
FROM user as usr
ORDER BY usr.$sortby $direction LIMIT ?,?

但是,对我来说,这似乎效率很低。基本上,我在这里所做的就是为级别表和类表中需要的每个列(!)编写一个子查询。如果我在一个子查询中查询级别表或类表的多列,它会再次返回所有值的组合。我觉得我的数据库技能存在差距,我明显缺少一些东西,我不知道一个功能......

你能帮我吗?如何为一组行编写有效的查询,该查询组合了三个表中的列,但不通过键(而不是范围)链接?

PS:我知道,如果我将此架构非规范化以将级别和类组合到用户表中,我可以大大简化场景,但我需要这个有一个特定的原因,相信我.

最佳答案

如果您可以修改 Level 和 Class 表以在行中具有实际范围(即 Level 表中具有 minkarma 和 maxkarma,Class 表中具有 minlevel 和 maxlevel),那么您应该能够在您的连接条件,它只会为每个用户返回一行。

示例:

SELECT * FROM user as u
INNER JOIN level as lv on
    u.karma >= lv.min_karma AND u.karma <= lv.max_karma
INNER JOIN levelclass as lvc on
    lv.num >= lvc.min_level AND lv.num <= lvc.max_level

您获得多行的原因是您通过仅过滤最小值来匹配多个级别和类别。

关于MySQL:如何为基于范围而不是外键的关系编写查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/912078/

相关文章:

java - MySQL更新触发错误;在更新的记录中设置值

php - 如何在 MySQL 中通过一次选择为每个 'category' 获取 5 条记录?

PHP/MySQL 在 TD 中输出数据

mysql - mysql 查询如何基于信息模式工作

php - 如何将此查询转换为 SQL SERVER

java - 从 DB 检索图像到 imageView

mysql - 在 SQL 中将行转换为列

MySQL 整理查询永远运行

php - 特定数据未插入列中

mysql - 从所有数据库的查询结果中获取顶部记录