Разбивка на страницы в MySQL с предложением JOINed ORDER - PullRequest
0 голосов
/ 13 ноября 2018

Возникли проблемы с разбивкой по страницам набора данных, созданного путем запроса объединенной таблицы.

Моя таблица продуктов выглядит следующим образом:

id   | sort_order
-----------------
1    | 5
2    | 4
3    | 0
4    | 0
5    | 4
...

и моя таблица объединенных запасов выглядит следующим образом:

id | product_id | start_date
----------------------------
1  | 1          | 2018-12-14
2  | 1          | 2019-01-28
3  | 2          | 2018-12-26
4  | 3          | 2018-12-28
5  | 4          | 2019-01-12
6  | 4          | 2019-01-14
7  | 5          | 2020-01-10
...

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

  • Во-первых, по sort_order
  • Во-вторых, самое раннее start_date, связанное с ним.

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

Затем я прибегнул к нумерации страниц на основе (что также будет хорошо сейчас), но это также приводит к дублированию, иогромное количество страниц.

Я довольно застрял в том, как продолжить с этим.

Моя пагинация на основе смещения SQL (сгенерированная Sequelize) ниже:

SELECT
    `Product`.`id` AS `id`,
    `Product`.`sort_order` AS `sortOrder`,
    `availability`.`id` AS `availability.id`,
    `availability`.`product_id` AS `availability.productId`,
    `availability`.`start_date` AS `availability.startDate`
FROM
    `product` AS `Product`
LEFT OUTER JOIN `stock` AS `availability` 
                 ON `Product`.`id` = `availability`.`productId`
ORDER BY
    sort_order = 0,
    sort_order
LIMIT 0, 10

С даннымии выше, я бы надеялся на следующее:

id   | sortOrder | `availability.id` | `startDate`
--------------------------------------------------
1    | 5         | 1                 | 2018-12-14
2    | 4         | 3                 | 2018-12-26
5    | 4         | 7                 | 2020-01-10
3    | 0         | 4                 | 2018-12-28
4    | 0         | 5                 | 2019-01-12

1 Ответ

0 голосов
/ 13 ноября 2018

Вы получаете дублирование, потому что вы JOIN обращаетесь к таблице, которая имеет несколько значений на product_id. Вы должны ограничить это значение одним значением, и на основе ваших критериев сортировки должны быть значения, связанные с минимальной датой start_date. Вы можете сделать это с помощью подзапроса для таблицы JOIN:

SELECT
    `Product`.`id` AS `id`,
    `Product`.`sort_order` AS `sortOrder`,
    `availability`.`id` AS `availability.id`,
    `availability`.`product_id` AS `availability.productId`,
    `availability`.`start_date` AS `availability.start_date`
FROM
    `product` AS `Product`
LEFT JOIN (SELECT id, product_id, start_date
           FROM`stock` s
           WHERE start_date = (SELECT MIN(start_date) 
                               FROM stock s1 
                                WHERE s1.product_id = s.product_id)
           ) AS `availability` 
    ON `Product`.`id` = `availability`.`product_id`
ORDER BY
    sort_order = 0,
    sort_order,
    availability.start_date
LIMIT 0, 10

Вывод данных для образца:

id  sortOrder   availability.id     availability.productId  availability.start_date
1   5           1                   1                       2018-12-14
2   4           3                   2                       2018-12-26
5   4           7                   5                       2020-01-10
3   0           4                   3                       2018-12-28
4   0           5                   4                       2019-01-12

Демонстрация по SQLFiddle

...