У меня есть три таблицы в MySQL, которые связаны, но технически не связаны между собой внешним ключом. Это: пользователи , уровни и классы .
Таблица пользователей имеет столбец кармы, числовой тип. Основываясь на этом числе карма , я хочу знать уровень пользователя , который я извлекаю из таблицы уровней. Это не сложное отношение, так как уровень связан с диапазоном значений кармы, например:
- уровень 1 (минимальная карма: 0)
- уровень 2 (минимальная карма: 100)
- уровень 3 (минимальная карма: 500)
- ...
Так, если у пользователя есть карма 400, возвращаемое значение должно быть 2. Чтобы сделать вещи немного более сложными, номер уровня указывает класс пользователя пользователя, определения которого хранятся в классах. Таблица. Еще раз это диапазон отношение:
- Муравей класса (минимальный уровень 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: Я знаю, что мог бы значительно упростить сценарий, если бы денормализовал эту схему для объединения уровней и классов в таблицу пользователей, но есть конкретная причина, почему мне это нужно, поверьте мне.