2011-12-28 2 views
3

Я использую 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        
+2

Я не совсем понимаю, о чем вы спрашиваете. Можете ли вы изменить свой вопрос и представить пример ожидаемого результата? – Todd

+0

Есть ли level_id в вашей пользовательской таблице? –

+0

Предоставьте информацию о том, в каких столбцах эти таблицы должны быть объединены, потому что в таблице «levels» нет столбца, который может использоваться для соединения с «пользователями». – piotrekkr

ответ

4

Если нет пробелов в 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 соединением внешнего соединения.

+0

Эта версия имеет серьезные проблемы с производительностью. Он должен соответствовать всем строкам из обеих таблиц. Фильтрация его вниз для возврата только уровня одного пользователя по-прежнему должна соответствовать всем строкам из таблицы уровней. –

+0

@TupshinHarper: судя по ожидаемому результату, запрос должен получить уровень для всех пользователей. Я дам, что использование 'order by' /' limit 1' или агрегат лучше работает для запроса одного пользователя, но не для запроса всех пользователей. Чтобы выполнить группировку и агрегацию для всех пользователей, СУБД построит промежуточный набор записей с 'U * (1/2) L', где U - количество записей в пользователях, а L - количество записей на уровне (при условии, что равномерное распределение пользователей по уровню). Самоподключение на уровне позволяет оптимизатору использовать 2 набора записей с размерами U и L для построения результата. – Simon

+0

Справедливо достаточно. Ваш ответ хорош для возврата всех уровней пользователей, которые действительно выглядят так, как они просят. Для специального случая возврата определенного уровня пользователя я по-прежнему рекомендую мою версию ниже. –

1

Вы хотите МИН, что пользователь может видеть:

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 
+0

Я считаю, что вам нужен минимальный уровень, чье требование «exp» превосходит пользовательский опыт, а не максимум. –

+0

Эрик, я считаю, что ему нужен самый низкий уровень опыта (то есть текущий уровень для пользователя). Макс. (L.id) должно быть min (l.id) – Gabe

+0

Да, вы, ребята, правы. Починил это. – Eric

1

вопрос сформулирован неясно, но из контекста, похоже, вы ищете самый высокий уровень, который достиг человек g при их текущем exp и min_exp.

Поскольку вы знаете, идентификатор пользователя, которого вы ищете, запрос может быть

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 | 
----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+` 
+0

Я еще не могу комментировать другие ответы, но ведущий ответ прямо пропорционален * обоим * размеру таблицы пользователей и размеру таблицы уровней. Если вы измените его, чтобы просто вернуть уровень одного пользователя (users.id), он по-прежнему пропорционален размеру таблицы уровней (запустите на нем объяснение). –

Смежные вопросы