Предположим, у меня есть четыре таблицы: tbl1
... tbl4
. Каждый имеет уникальное числовое поле id
. tbl1
, tbl2
и tbl3
каждый имеет поле внешнего ключа для следующей таблицы в последовательности. Например, tbl1
имеет поле внешнего ключа tbl2_id
и т. Д. В каждой таблице также есть поле order
(и другие поля, не относящиеся к вопросу).
Нетрудно объединить все четыре таблицы, чтобы получить все строки таблицы tbl1 вместе с соответствующими полями из трех других полей. Также легко упорядочить этот набор результатов с помощью определенной комбинации c ORDER BY
полей order
. Также легко вернуть только строку, которая соответствует некоторому конкретному id
в tbl1
, например, WHERE tbl1.id = 7777
.
ВОПРОС: какой запрос наиболее эффективно возвращает (например, 100 строк), начиная со строки соответствует id=7777
, в порядке, определяемом заданной комбинацией c полей order
?
Использование ROW_NUMBER
или (эмуляция этого в MySQL версии <8), чтобы получить положение строки id = 7777, а затем использование этого в новой версии того же запроса, чтобы установить смещение в предложении <code>LIMIT будет одним из подходов. (С блокировкой чтения между ними.) Но можно ли это сделать за один запрос?
# FIRST QUERY: get row number of result row where tbl1.id = 7777
SELECT x.row_number
FROM
(SELECT @row_number:=@row_number+1 AS row_number, tbl1.id AS id
FROM (SELECT @row_number:=0) AS t, tbl1
INNER JOIN tbl2 ON tbl2.id = tbl1.tbl2_id
INNER JOIN tbl3 ON tbl3.id = tbl2.tbl3_id
INNER JOIN tbl4 ON tbl4.id = tbl3.tbl4_id
WHERE <some conditions>
ORDER BY tbl4.order, tbl3.order, tbl2.order, tbl1.order
) AS x
WHERE id=7777;
Сохранить номер строки из вышеприведенного запроса и использовать его для привязки :offset
в следующем запросе.
# SECOND QUERY : Get 100 rows starting from the one with id=7777
SELECT x.field1, x.field2, <etc.>
FROM
(SELECT @row_number:=@row_number+1 AS row_number, field1, field2
FROM (SELECT @row_number:=0) AS t, tbl1
INNER JOIN tbl2 ON tbl2.id = tbl1.tbl2_id
INNER JOIN tbl3 ON tbl3.id = tbl2.tbl3_id
INNER JOIN tbl4 ON tbl4.id = tbl3.tbl4_id
WHERE <same conditions as before>
ORDER BY tbl4.order, tbl3.order, tbl2.order, tbl1.order
) AS x
LIMIT :offset, 100;