Динамическое создание столбцов lft и rgt в MySQL - PullRequest
0 голосов
/ 01 апреля 2020

Может ли кто-нибудь подсказать мне, как динамически создавать столбцы lft и rgt (анализируются слева направо в дереве из root) для таблицы, используя MySQL Query?

Структура моего таблица выглядит так:

id----name----parent_id

, и я хочу такую ​​структуру:

name----lft----rgt

Ответы [ 2 ]

0 голосов
/ 01 апреля 2020

Мне не нравится модель с вложенными множествами для представления иерархических данных в реляционной базе данных. Он был популярен благодаря книге Джо Селко 2004 года «Деревья и иерархии в SQL для умных» и посту в блоге Майка Хиллиера , который датируется как минимум 2010 годом.

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

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

Другая проблема с моделью вложенного набора состоит в том, что значения left и right не являются ссылками на какие-либо другие элементы данных. На самом деле, нет никакого смысла, кроме как в их отношении к значениям left и right других узлов. Таким образом, нет целостности данных, и аномалии данных могут легко испортить вашу иерархию.

Единственная иерархическая модель с целостностью данных - это та, которую вы уже получили - хранение parent_id в строке каждого узла. Аномалии данных не могут существовать, когда каждый узел знает своего родителя, и не будет никакого аргумента или конфликта с любыми другими строками.

Недостатком этой модели, называемой моделью Adjecency List, является то, что MySQL не поддерживает рекурсивные запросы до версии 8.0. Смотрите примеры в https://dev.mysql.com/doc/refman/8.0/en/with.html

0 голосов
/ 01 апреля 2020

Вы можете самостоятельно присоединиться к таблице и агрегировать:

select
    t.id
    t.name,
    min(t1.id) left_id,
    max(t1.id) right_id
from mytable t
left join mytable t1 on t1.parent_id = t.id
group by t.id, t.name

Это предполагает наличие ровно двух дочерних элементов на узел. Если у некоторых узлов может быть только один дочерний элемент, вы можете добавить небольшую логику c:

select
    t.id
    t.name,
    min(t1.id) left_id,
    case when min(t1.id) <> max(t1.id) then max(t1.id) end right_id
from mytable t
left join mytable t1 on t1.parent_id = t.id
group by t.id, t.name
...