Как отфильтровать соседние строки (первый, предыдущий, следующий, последний) из результата запроса? - PullRequest
0 голосов
/ 14 апреля 2019

Я работаю над решением быстрых ссылок для большого набора записей. Записи заказываются пользователем (критерии здесь не важны), и я составил список идентификаторов. Теперь мне удалось добавить позицию к каждому идентификатору.

SELECT
     cp.id,
     cp.page_name,
     @rownum := @rownum + 1 AS `position`
FROM couch_pages cp
JOIN (SELECT @rownum := 0) r
WHERE cp.template_id = '2'
ORDER BY cp.publish_date DESC

Таблица couch_pages имеет id, template_id, page_name, publish_date и множество других столбцов. Клиент может запросить произвольный порядок идентификаторов. Я должен следовать за лидерством и пересчитывать позицию каждый раз.

Чего я не знаю, так это того, можно ли рассчитать не только позицию для всего набора, но и получить позицию произвольного идентификатора, например, cp.id = '1600', и получать записи prev-next-last-first в один запрос.

Результат запроса выше выглядит просто -

"id"    "page_name" "position"

"1578"   "late-in-the-evening"  "1"
"1600"   "thats-why-god-made-"  "2"
"1599"   "god-bless-the-absen"  "3"
............................
"124601" "loves-me-like-a-ro"   "122703"

В данный момент я отправляю весь результат в массив PHP и могу найти соответствующую запись (например, с id = "1600") и ее соседей - предыдущая запись (id = "1578"), следующая запись , первая и последняя записи.

Я бы хотел , а не отправить целое подмножество клиенту, потому что я предполагаю, что количество записей может взорваться, и сценарий станет намного медленнее.

Можно ли отфильтровать требуемые (предыдущая, следующая, последняя, ​​первая) записи для данного идентификатора из результатов?

1 Ответ

0 голосов
/ 15 апреля 2019

Использование Cross JOIN Я создал новый столбец для ваших записей, чтобы определить, какая из них является первой, а какая - последней.Как указано в моем первом комментарии, count(*) должно быть достаточно, потому что мы можем проверить его по столбцу position.

В MySQL, JOIN, CROSS JOIN и INNERJOIN - это синтаксические эквиваленты (они могут заменять друг друга).В стандартном SQL они не эквивалентны. INNER JOIN используется с предложением ON, CROSS JOIN используется в противном случае .

Попробуйте следующий код:

    SELECT
    a.*,
    (
    CASE

            WHEN a.position = 1 
            AND a.position = c.total_records THEN
                3 -- Mark only if you have one record 3 = (1 and 2) at the same time

                WHEN a.position = 1 THEN
                1 -- Mark first record with 1

                WHEN a.position = c.total_records THEN
                2 -- Mark last record with 2
                ELSE 0 
            END 
            ) AS row_status 
        FROM
            ( SELECT count( * ) AS total_records FROM couch_pages ) c
            CROSS JOIN (
            SELECT
                x.id,
                x.page_name,
                x.position 
            FROM
                (
                SELECT
                    t.id,
                    t.page_name,
                    @rownum := @rownum + 1 AS position 
                FROM
                    couch_pages t
                    JOIN ( SELECT @rownum := 0 ) r 
                -- ORDER BY
                    -- cast( SUBSTR( t.page_name, 5 ) AS INT ) -- Order by the INT part of your page_name

                ) x 
            ) a 
    LIMIT 4 OFFSET 3;-- This is the line you should adjust using PHP, you can keep the values in POST or GET like FQDN/?page=3&records_per_page=4
...