Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Mysql остановка выборки при первом соответствии условия.

Alex Al Профи (566), закрыт 1 неделю назад
Возможно-ли одним запросом получить такой результат (без подзапроса)?

Пример приведу ненастоящий, простой, только для наглядности.

Таблица `messages` с полями `id`, `dialog_id`, `author_id`, `content`, `read_status`.

Допустим мы хотим сделать выборку всех сообщений where `dialog_id`=3, выборку сортируем ORDER BY `id` DESC ну и ставим лимит LIMIT 50

Но если нам нужно получить больше сообщений когда кол-во непрочитанных (`read_status`=false) за границами лимита.

Конечно можно сделать предварительный запрос, можно подзапрос. Но может я что-то упускаю.

Есть ли какой-то функционал в mysql что бы остановить выборку при соответствии дополнительного условия?
Лучший ответ
Константин Бардин Знаток (439) 2 недели назад
В MySQL нет прямого способа остановить выборку при соответствии дополнительного условия без использования подзапросов или предварительных запросов. Однако можно воспользоваться следующим приближенным методом:

1. Выполните первый запрос, чтобы получить первые 50 записей с сортировкой по `id` в обратном порядке.
2. Посчитайте количество непрочитанных сообщений в выборке. Если это количество больше нуля, выполните второй запрос, чтобы получить все непрочитанные сообщения, которые не вошли в первую выборку.

Примерно такой запрос может выглядеть:
 SELECT *  

FROM messages

WHERE dialog_id = 3

ORDER BY id DESC

LIMIT 50;



-- Дополнительный запрос только в случае, если есть непрочитанные сообщения за пределами лимита

SELECT *

FROM messages

WHERE dialog_id = 3

AND read_status = false

AND id < (SELECT MIN(id) FROM (SELECT id FROM messages WHERE dialog_id = 3 ORDER BY id DESC LIMIT 50) AS subquery);
Этот метод, конечно, включает два запроса, но он позволяет выполнить дополнительный запрос только в том случае, если в пределах лимита есть непрочитанные сообщения.
Остальные ответы
Алексей Пинчук Мудрец (15807) 1 неделю назад
Для решения этого вопроса можно применить два способа, которые условно можно назвать дифференциальным и интегральным.

Первый способ, дифференциальный, основан на определении для каждой строки, подходит ли она. Для этого требуются номера строк, получить которые можно с помощью оконных функций.
 SELECT * 
FROM (SELECT *,
ROW_NUMBER() OVER (ORDER BY id DESC) AS RowNum
FROM messages
WHERE dialog_id=3
) AS _
WHERE RowNum<=50 OR read_status=false
ORDER BY id DESC;

Другой способ, интегральный, оперирует совокупностями записей, что более соответствует духу SQL.
 (SELECT * FROM messages WHERE dialog_id=3 ORDER BY id DESC LIMIT 50)  
UNION
SELECT * FROM messages WHERE dialog_id=3 AND read_status=false
ORDER BY id DESC;

Обращаю внимание, что использовать надо именно UNION, а не UNION ALL, чтобы исключить дубликаты.
Похожие вопросы