MySQL как начать вывод строк после определенного ID?

228
08 сентября 2021, 06:20

Есть сайт вопросов и ответов, в нём, в конце списка вопросов, повесил кнопку "Показать еще" (вопросы). Эта кнопка передает ajax запросом в php скрипт, параметр позиции элемента с которого необходимо вернуть новую пачку вопросов. Если использовать в качестве этого параметра, её порядковый номер, например 10, соответственно SQL запрос, в теле php скрипта, будет типа SELECT .... LIMIT 10, 40 (40 - количество), то появляется проблема, так как если, после того как кнопка будет сформирована и выведена в браузере пользователя, будут добавлены новые вопросы, то скрипт продублирует уже выведенные вопросы, так как позиция таблицы уже сместилась. Пришла идея использовать в качестве стартовой позиции - идентификатор последнего вопроса, что-то вроде startID, но не знаю как это реализовать, что-то вроде SELECT .... LIMIT $startID, 40, запрос должен вывести 40 записей, после того как встретит запись с заданным startID. Решение WHERE id > $startID LIMIT 40 не годится так, как строки отсортированы не по полю id. Позволяет ли язык SQL реализовать эту идею?

Answer 1

Всё верно, пагинация через offset предполагает такие артефакты, не говоря о том что такая пагинация медлительна. Направление для решения вы выбрали верное, но вам нужен не абстрактный ID, а сперва вам необходимо явно и недвусмысленно зафиксировать сортировку результата. Запрос where .. limit для пагинации не имеет смысла. У вас обязан быть order by при том включающий в себя какой-либо признак уникальности. Например, имея уникальный идентификатор id и если вы хотите сортировать по не уникальному полю created_at с датой создания сущности, то вам необходима сортировка:

order by created_at desc, id desc

Затем, при необходимости загрузить следующий фрагмент данных, вы передаёте на backend оба значение: и created_at и id последней строки которую вы показали пользователю. И запрашиваете следующую порцию данных:

 WHERE (created_at, id) < (?, ?)
 ORDER BY created_at DESC, id DESC
 LIMIT 10

Просто, элегантно, соответствует стандарту, быстро по составному индексу (created_at, id). Нормально поддерживается только в postgresql... В mysql выполняется логика верно, но без поддержки индекса (впрочем, может у меня устарели сведения), так что объясняем необходимую логику фильтрации вручную:

 WHERE created_at <= ?
    AND NOT (created_at = ? AND id >= ?)
 ORDER BY created_at DESC, id DESC
 limit 10

По материалам статьи Markus Winand, которые весьма рекомендую к прочтению.

READ ALSO
Как разделить Telegram кнопки (команды) и вводимый текст?

Как разделить Telegram кнопки (команды) и вводимый текст?

Создал бота Telegram, который по нажатию на кнопки выводит заданные результате по командам: /help /test и тд

198
Несколько ссылок на одном картинке

Несколько ссылок на одном картинке

ЗдрастеМне задали задачку сделать несколько ссылок на одном фото

169
Как получить последний символ из переменной?

Как получить последний символ из переменной?

Как отсюда выделить последний символ -1?

185