Как выбрать иерархические записи из двух таблиц с помощью объединения - PullRequest
0 голосов
/ 15 февраля 2020

На самом деле я хочу выбрать совпавшие записи из двух таблиц с иерархическими данными из первой таблицы

У меня есть две таблицы:

  1. таблица tmpos_category с столбцами (category_refid (рк), category_name, parent_ref_id) . я храню иерархические данные в нем.

  2. таблица tmpos_menu_child с столбцами (id (pk), заголовок, category_ref_ids (fk)) . Поле category_ref_ids из таблицы tmpos_menu_child ссылается на поле category_refid таблицы tmpos_category .

это таблица tmpos_category с иерархическими категориями

enter image description here

таблица tmpos_menu_child с category_ref_ids в качестве fk refresces category (category_refid) столбец

enter image description here

SELECT DISTINCT ct.category_name,ct.category_refid,ct.parent_ref_id
from tmpos_category ct
JOIN tmpos_menu_child tmc
ON ct.category_refid = tmc.category_ref_ids

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

Ответы [ 2 ]

0 голосов
/ 15 февраля 2020

Если в вашей иерархии может быть только 2 уровня, то есть родитель не может сам иметь родителя, то это сделают два JOIN.

SELECT i.id AS item_id, i.title AS item_title
     , c.category_refid, c.category_name
     , c.parent_ref_id, p.category_name AS parent_name
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
  LEFT JOIN tmpos_category p ON p.category_refid = c.parent_ref_id

Если иерархия может быть глубокой, вам следует использовать иерархический запрос, который в большинстве СУБД выполняется с помощью рекурсивного CTE (общее табличное выражение).

WITH RECURSIVE Item_and_Cat (item_id, item_title, category_level,
                             category_refid, category_name, parent_ref_id) AS (
   SELECT i.id AS item_id, i.title AS item_title
        , c.category_refid, c.category_name
        , 1 AS category_level, c.parent_ref_id
     FROM tmpos_menu_child i
     JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
   UNION ALL
   SELECT i.item_id, i.item_title
        , p.category_refid, p.category_name
        , i.category_level + 1 AS category_level, p.parent_ref_id
     FROM Item_and_Cat i
     JOIN tmpos_category p ON p.category_refid = i.parent_ref_id
)
SELECT item_id, item_title, category_refid, category_name, category_level
  FROM Item_and_Cat

Примечание: Ключевое слово RECURSIVE требуется для PostgreSQL и MySQL, но не разрешено для Oracle БД и SQL Сервер.


ОБНОВЛЕНИЕ

С комментарий :

я хочу, чтобы там были родители в виде записи (в отдельной строке)

Чтобы получить родительские записи в виде отдельных строк, дважды выполните запрос и объедините его с UNION.

SELECT i.id AS item_id, i.title AS item_title
     , c.category_refid, c.category_name, 0 AS is_parent
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
UNION ALL
SELECT i.id AS item_id, i.title AS item_title
     , p.category_refid, p.category_name, 1 AS is_parent
  FROM tmpos_menu_child i
  JOIN tmpos_category c ON c.category_refid = i.category_ref_ids
  JOIN tmpos_category p ON p.category_refid = c.parent_ref_id
0 голосов
/ 15 февраля 2020

Таким образом, при использовании этой схемы с parent_ref_id на category table будет сложно продвинуться вверх по иерархии и получить все категории предков без написания запросов, к которым присоединяется жесткий код 1 для каждого родителя.

Если у вас когда-либо будет 2 или 3 поколения (например, ребенок, родитель, дедушка или бабушка), то это нормально, но с большим количеством (или с переменным уровнем) это может стать грязным. Одним из решений является использование «рекурсивного синтаксиса», но, насколько мне известно, не все реализации SQL поддерживают его.

У Билла Карвина есть отличная слайд-колода, в которой подробно описываются плюсы и минусы вашей схемы (обычно упоминается как "списки смежности").

вы можете найти это на слайдах 6-17 здесь:

https://www.slideshare.net/billkarwin/models-for-hierarchical-data

Он довольно подробно описывает вашу проблему и предлагает несколько других стратегий для моделирования иерархий, если у вас возникнут проблемы с вашей текущей схемой. Мне лично нравится последний, подробно описанный в этой колоде, который называется «таблица закрытия»

РЕДАКТИРОВАТЬ

Если вы на самом деле пытаетесь включить только один или два родительские уровни, тогда ваш запрос будет выглядеть очень похоже на любой запрос, объединяющий 3 или более таблиц, только вам нужно будет присоединить таблицу categories к себе. Это может быть довольно легко найти примеры, если вы Google "присоединить таблицу к себе" или что-то подобное

...