Гость
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Помогите составить сложный запрос / 19 сообщений из 19, страница 1 из 1
20.06.2019, 00:05
    #39828593
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Привет всем! Название темы умнее не придумал, т.к. в двух словах не опишешь :(

В общем, ситуация следующая. Есть простая таблица игроков, нас интересуют только поля "id" и "level".
Нужно получить N (например, 10) любых игроков, "id" которых должен быть в заданном списке, а уровень (level) находится в определённом диапазоне, причём уровень не должен повторяться.
Что-то вроде этого (константы для примера, у меня это переменные из PHP):

Код: sql
1.
SELECT id,level FROM `users` WHERE id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) AND level BETWEEN 10 AND 20 GROUP BY level LIMIT 10



Здесь всё ОК, но вот потом, если запрос вернёт менее 10 игроков (например, нашёл 4), оставшиеся 6 надо "добить" игроками из базы по тем же условиям, но уже без проверки ID, типа того:

Код: sql
1.
SELECT id,level FROM `users` WHERE level BETWEEN 10 AND 20 GROUP BY level LIMIT 10



То есть те, перечисленные, игроки находятся как бы в приоритете :)

Попробовал сделать двумя запросами и в PHP их объединить в один массив, но тут мешают две проблемы - во-первых, второй запрос может выдать частично тех же людей, что и первый, но это не так страшно, есть варианты решения. А вот сделать, чтобы второй запрос не повторял значений level из первого - это уже сложнее :( Либо вместо BETWEEN делать перечисление "свободных" уровней, либо делать лимит в 2 раза больше (чем нужно) а потом в PHP отсеивать лишних...
Вопрос - нельзя ли вообще всё это как-нибудь организовать в одном сложном запросе? :) Заранее спасибо :)
...
Рейтинг: 0 / 0
20.06.2019, 05:41
    #39828620
Щукина Анна
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Egis,

что делать в ситуации, если в таблице в принципе не набирается достаточного количества игроков с уникальными уровнями? К примеру, все игроки имеют одинаковый уровень. Или уровень ни одного из игроков не попадает в заданный диапазон уровней.
...
Рейтинг: 0 / 0
20.06.2019, 13:41
    #39828778
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Щукина Анна,

Просто вернуть тех, которые нашлись (или ничего), в общем то что и делает запрос при указании LIMIT
...
Рейтинг: 0 / 0
16.07.2019, 00:00
    #39837656
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Видимо, проще не получится, ну что ж...

А еще такой вопрос: допустим, мне надо получить по одному игроку каждого уровня, скажем от 1 до 20 (если на каком-то уровне ни одного игрока нет - ничего страшного) - каким образом ЭФФЕКТИВНЕЕ это сделать?

Простейший (и, возможно, наилучший) вариант, для примера:
Код: plsql
1.
SELECT id,level FROM `users` WHERE level BETWEEN 1 AND 20 GROUP BY level



Есть ли, например, смысл обозначать лимит в 20 человек, или GROUP и так прекращает поиск, если 20 человек найдено?

"Случайность" выборки не имеет значения, т.е. нужен любой первый попавшийся игрок с нужным уровнем.
...
Рейтинг: 0 / 0
16.07.2019, 07:09
    #39837684
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Уточните версию MySQL.
...
Рейтинг: 0 / 0
16.07.2019, 13:12
    #39837862
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Сервер: MySQL (Localhost via UNIX socket)
Версия сервера: 5.5.41-0+wheezy1
Версия протокола: 10
MySQL-кодировка: UTF-8 Unicode (utf8)
Apache/2.2.22 (Debian)
Версия MySQL-клиента: 5.5.41
PHP расширение: mysqli
...
Рейтинг: 0 / 0
16.07.2019, 14:25
    #39837888
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Ну если в принципе всё равно какой id для каждого level вернётся, то максимальный (или там минимальный) подойдёт? Тогда я бы сделал так:

Код: sql
1.
2.
3.
4.
5.
6.
SELECT MAX(id) id, level 
FROM users 
WHERE level BETWEEN 10 AND 20 
GROUP BY level
ORDER BY id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) DESC
LIMIT 10
...
Рейтинг: 0 / 0
16.07.2019, 14:27
    #39837889
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Ну, или коли уж версия 5.5 и чхать хотела на неполную группировку, MAX() убрать, и фиг с им, с несоответствием стандарту:

Код: sql
1.
2.
3.
4.
5.
6.
SELECT id, level 
FROM users 
WHERE level BETWEEN 10 AND 20 
GROUP BY level
ORDER BY id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) DESC
LIMIT 10
...
Рейтинг: 0 / 0
17.07.2019, 01:13
    #39838118
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Спасибо за ответ!

Я только не очень понял, что делает строчка
Код: sql
1.
 ORDER BY id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) DESC



Если это ответ на первый вопрос (т.е. моя мечта искать в одном запросе сначала среди "приоритетных" ID, и если нужных уровней среди них нет то дополнить любыми с нужным уровнем), то у меня это не работает - всё равно возвращаются те же самые, не приоритетные случайные ID. Если указать MAX, то возвращаются другие, крупные (максимальные) id для тех же уровней, но указанные в списке никак не участвуют (разве что, попадаются случайно). Т.е. ORDER BY у меня вроде как ничего не меняет (только почему-то меняет порядок записей на хаотичный, но порядок записей не имеет для меня значения).
Пример без ORDER BY:
Код: sql
1.
2.
3.
4.
5.
SELECT id, level 
FROM users
WHERE level BETWEEN 1 AND 10 
GROUP BY level
LIMIT 10 (ничего не меняет, что логично, возможно влияет на быстродействие?)


Возвращает:
|1169123|1
|934302|2
|3484|3
|93331|4
|788599|5
|1630225|6
|996868|7
|405900|8
|260797|9
|568414|10

Пример с ORDER ID (перечислены реальные ID, их level точно входят в нужный диапазон):
Код: sql
1.
2.
3.
4.
5.
6.
SELECT id, level 
FROM users
WHERE level BETWEEN 1 AND 10 
GROUP BY level
ORDER BY id IN (18211095,31749108,2021239,3760319,3834192)
LIMIT 10


|3484|3
|93331|4
|260797|9
|405900|8
|568414|10
|788599|5
|934302|2
|996868|7
|1169123|1
|1630225|6
...
Рейтинг: 0 / 0
17.07.2019, 01:18
    #39838119
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Не нашёл как редактировать сообщение... Когда пробовал последний раз забыл DESC, но это никак не повлияло на результат.
...
Рейтинг: 0 / 0
17.07.2019, 02:47
    #39838130
vkle
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
EgisЯ только не очень понял, что делает строчка
Код: sql
1.
 ORDER BY id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) DESC




Если это ответ на первый вопрос (т.е. моя мечта искать в одном запросе сначала среди "приоритетных" ID, и если нужных уровней среди них нет то дополнить любыми с нужным уровнем), то у меня это не работает

Попробуйте такой вариант:
Код: sql
1.
ORDER BY FIELD(id, 51,16,27,8,91,10,32,19,22,12,192,232,212) DESC




EgisНе нашёл как редактировать сообщение...И не найдете, нет такого функционала для пользователей.
...
Рейтинг: 0 / 0
17.07.2019, 03:41
    #39838132
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
[quot vkle]

Попробуйте такой вариант:
Код: sql
1.
ORDER BY FIELD(id, 51,16,27,8,91,10,32,19,22,12,192,232,212) DESC



Увы, точно такой же результат как для "ORDER BY id IN" :(
Всегда выбирает минимальный ID из ВСЕХ с подходящим уровнем.
...
Рейтинг: 0 / 0
17.07.2019, 04:02
    #39838134
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Если пишу вот так:

Код: sql
1.
2.
3.
4.
5.
SELECT id, level, FIELD( id, 18211095, 31749108, 2021239, 3760319, 3834192 ) AS f
FROM users
WHERE level BETWEEN 1 AND 10 
GROUP BY level
ORDER BY f DESC 


то f всегда 0, и результат прежний.

Если убрать GROUP BY level, то первые 5 значений берутся из "приоритетных", и f = 5,4,3,2,1. Но, соответственно, вылезают все записи с повторяющимися уровнями :(
id - первичный уникальный ключ типа BIGINT, если что, мало ли...
...
Рейтинг: 0 / 0
17.07.2019, 07:21
    #39838144
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
EgisЯ только не очень понял, что делает строчка
Код: sql
1.
 ORDER BY id IN (51,16,27,8,91,10,32,19,22,12,192,232,212) DESC

Это, судя по первым двум словам, ORDER BY Clause. Т.е. предложение сортировки.
Сортировка выполняется по результату вычисления указанного выражения, причём по причине наличия DESC - в порядке убывания.
Оператор IN возвращает TRUE, если условие истинно (искомое значение присутствует в списке), иначе FALSE.
TRUE - это алиас целочисленного значения 1, FALSE - алиас целочисленного значения 0.
Т.е. фактически при сортировке сначала будут выведены записи со значением 1 (TRUE) - т.е. те, чьи id присутствуют в списке, а затем остальные (которых в списке нет).
...
Рейтинг: 0 / 0
17.07.2019, 13:53
    #39838297
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Akina,

Спасибо за разъяснения.
Всё работает как вы говорите, но, к сожалению для моего случая, уже только после процедуры группировки по уровню (как я понял) :(
С FIELD аналогично, если не делать группировку то всё было бы прекрасно...
...
Рейтинг: 0 / 0
17.07.2019, 15:11
    #39838350
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Egisдля моего случая, уже только после процедуры группировки по уровнюПрочитал три раза, ни разу не понял...
...
Рейтинг: 0 / 0
17.07.2019, 15:38
    #39838364
Egis
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Если написать GROUP BY level, то сначала, как я понимаю, происходит сама группировка по level (уровню), и только потом ORDER BY. Грубо говоря, сортировать после группировки уже нечего, возвращаются первые попавшиеся id с нужным level, ORDER BY уже не срабатывает, т.к. после группировки уже не остается "приоритетных" ID
...
Рейтинг: 0 / 0
17.07.2019, 19:55
    #39838452
vkle
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
Egis,

Подозреваю, что тупое решение "в лоб" тут будет и достаточно простым. Два запроса из первого поста соединить UNION и третим SELECT по результату объединения сделать итоговую десятку и сортировку.
Вроде бы, UNION сохраняет порядок записей из вложенных запросов, но если будет проблема с гарантированным получением в итоговом третьем запросе записей "обязательной" десятки, то, вероятно, в оба вложенных запроса придется добавить по одному полю с фиксированным значением, а в итоговом сделать по нему первый уровень сортировки.
...
Рейтинг: 0 / 0
18.07.2019, 07:30
    #39838548
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите составить сложный запрос
EgisГрубо говоря, сортировать после группировки уже нечего, возвращаются первые попавшиеся id с нужным level, ORDER BY уже не срабатывает, т.к. после группировки уже не остается "приоритетных" IDА что Вы хотите? изначально поставлена задача, гарантированно получающая недетерминированный результат. Именно он и получается - жаловаться не на что, сам попросил.
Меняй условия задачи.
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Помогите составить сложный запрос / 19 сообщений из 19, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]