donkarabon
@donkarabon

Вопрос знатокам SQL. Как исправить нехватку полученных данных (постранично) из-за дублирования при использовании JOIN?

Здравствуйте! Есть сайт на одной CMS, магазинчик. В БД сайта есть следующие таблицы:

Таблица товаров (cms_con_goods)
Поля: id(товара), прочие параметры (название, свойства и т.п.), category_id (id категории товара)

Таблица категорий (cms_con_goods_cats)
Поля: id(категории), прочие параметры (название, ее свойства и т.п.), ns_left и ns_right (для составления дерева категорий от родителя к дочкам)

Сам вывод записей (товаров) осуществляется с присоединением таблицы cms_con_goods_cats_bind, которая имеет следующую структуру:

item_id (id записи), category_id (id категории)

При каждом добавлении товара продавцом, допустим, для нового товара 155 с категорией 4 создается строка в этой таблице:
item_id, category_id
155, 4


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

В админке сайта включен вывод записей дочерних категорий в родительской. Т.е. если бы эта опция была отключена, то вывод записей был бы прост: заходя в категорию с id = n, получаем записи с id категории n, ну и записи в которых n указана как дополнительная (через присоединение таблицы cms_con_goods_cats_bind).

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

Запрос получения записей следующий:

SELECT i.*, u.nickname as user_nickname, f.title as folder_title
FROM cms_con_goods i
JOIN cms_con_goods_cats_bind as b ON b.item_id = i.id
JOIN cms_con_goods_cats as c ON c.id = b.category_id AND c.ns_left >= '{$category['ns_left']}' AND c.ns_right <= '{$category['ns_right']}'
JOIN cms_users as u ON u.id = i.user_id
LEFT JOIN cms_content_folders as f ON f.id = i.folder_id
WHERE (i.is_parent_hidden IS NULL) AND (i.is_approved = '1') AND (i.is_pub = '1')
ORDER BY i.date_raised desc
LIMIT 0, 15


$category - переменная, в которой содержится информация (id, title, ns_left, ns_right) той категории, страницу которой открыл пользователь.

JOIN cms_con_goods_cats_bind as b ON b.item_id = i.id
JOIN cms_con_goods_cats as c ON c.id = b.category_id AND c.ns_left >= '{$category['ns_left']}' AND c.ns_right <= '{$category['ns_right']}'


Эта часть, как я понял, отвечает за то чтобы мы отфильтровали записи так, чтобы вывести их из текущей категории и ее дочек.

Проблема заключается в том, что когда продавец, при добавлении категории, указывает основную категорию, скажем "аккаунты с CS:GO" (младшую), а в качестве дополнительной "steam аккаунты" (старшую), то из-за включенной опции "вывода дочерних элементов в родительской категории" в результате запроса мы получаем на странице 14 вместо 15 элементов (на странице мы выводим 15 эл-ов, см. LIMIT 0,15 в запросе).

0b2ffe9650a84eb49a713945db50eee9.png

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

Что, какую проверку, или присоединение добавить к данному запросу, чтобы исправить эту проблему? Можно ли как-то отфильтровать на этапе получения товаров (в данном запросе) все это дело так, чтобы не прибегать к ограничению продавцам добавления доп.категорий? В идеале, хотим оставить включенной опцию вывода дочек в родительских + оставить возможность продавцам магазина выбирать любую категорию в качестве дополнительной, как бы она ни относилась к основной, а на этапе получения списка товаров, просто грамотно фильтровать все.
  • Вопрос задан
  • 307 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Sumor
Делаете сначала SELECT DISTINCT i.id всего вашего запроса без ORDER BY и LIMIT.
А затем на основе полученных id формируете выдачу, например (но не обязательно только так), через WHERE i.id IN (вложенный SELECT с выбором id) уже с учётом ORDER BY и LIMIT.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы