Вложенные наборы MySQL - Как найти родительский узел?
-
05-07-2019 - |
Вопрос
У меня есть ваша обычная настройка типа иерархии вложенного набора со следующими столбцами:
имя таблицы:
myset
столбцы:
id, name, lft, rgt
Кто-нибудь знает запрос для определения родитель узла?
Я прочитал пару мест, что удобно также иметь parent_id родительский идентификатор столбец в вашей таблице, чтобы отслеживать это, но это кажется избыточным, и кажется, что он может не синхронизироваться с вложенным набором, если запрос был неправильно выполнен при добавлении / удалении / перемещении чего-либо внутри набора.
Решение
Посмотрите на этот вопрос.Он похож на ваш.Я разместил там запрос, который вам может понадобиться.
SELECT title, (SELECT TOP 1 title
FROM tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt
ORDER BY t2.rgt-t1.rgt ASC) AS parent
FROM tree t1
ORDER BY rgt-lft DESC
Я надеюсь, что здесь есть то, что вам нужно.
Для следующей таблицы:
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
это приводит к получению:
title | parent
----------------------------------------------
ELECTRONICS | NULL
PORTABLE ELECTRONICS | ELECTRONICS
TELEVISIONS | ELECTRONICS
MP3 PLAYERS | PORTABLE ELECTRONICS
FLASH | MP3 PLAYERS
CD PLAYERS | PORTABLE ELECTRONICS
2 WAY RADIOS | PORTABLE ELECTRONICS
TUBE | TELEVISIONS
LCD | TELEVISIONS
PLASMA | TELEVISIONS
Другие советы
TOP - это команда MSSQL, ограничение использования для MySQL:
SELECT title, (SELECT title
FROM tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt
ORDER BY t2.rgt-t1.rgt ASC
LIMIT 1)
AS parent FROM tree t1
ORDER BY (rgt-lft) DESC
Должно сработать ..
просто чтобы добавить к этим ответам, которые мне очень помогли,
мне нужно было найти непосредственного родителя узла, а также в некоторых случаях родителя самого верхнего уровня цепочки узлов,
я использовал следующее в качестве основы для получения элементов в порядке от потомка к родителю
SELECT parent.* FROM
nested_set node,
nested_set parent
WHERE (
node.set_left BETWEEN parent.set_left AND parent.set_right
)
AND node.set_id={CHILD_NODE_ID_HERE}
ORDER BY parent.set_right - parent.set_left
#LIMIT 1,1
затем речь идет о добавлении LIMIT 1,1
чтобы захватить только вторую строку, которая была бы непосредственным родителем
следует также отметить, что при приведенном выше запросе, если сам узел является родительским на самом верхнем уровне, то он НЕ будет иметь непосредственный родитель, так что с LIMIT 1,1
он должен возвращать пустой результирующий набор
чтобы получить родительский элемент самого верхнего уровня, я отменил предложение order by, включил проверку, является ли сам узел верхним родительским элементом, и ограничил результат первой строкой
SELECT parent.* AS top_level_right FROM
nested_set node,
nested_set parent
WHERE (
node.set_left >= parent.set_left
AND node.set_left <= parent.set_right
)
AND node.set_id={CHILD_NODE_ID_HERE}
ORDER BY parent.set_left - parent.set_right
LIMIT 1
в последнем запросе я использовал >= <=
операторы, чтобы выбранный диапазон охватывал дочерний узел, если он также является родительским верхнего уровня
У меня возникла проблема с запросом Лукаша.Моя версия mysql не понимала команду TOP.Вместо этого мне пришлось использовать LIMIT.Вот пересмотренный код.
SELECT
`id`,
(SELECT
`id`
FROM
`[*** YOUR TABLE ***]` AS `t2`
WHERE
`t2`.`left_id` < `t1`.`left_id`AND
`t2`.`right_id` > `t1`.`right_id`
ORDER BY
`t2`.`right_id`-`t1`.`right_id`ASC
LIMIT
1) AS `parent`
FROM
`[*** YOUR TABLE ***]` AS `t1`
WHERE
`t1`.`id` = [*** ID OF THE NODE WHOS PARENT YOU WISH TO LOOKUP ***]
ORDER BY
`right_id`-`left_id` DESC
Очевидно, измените содержимое в [ ] 's в соответствии с вашими потребностями.Также удалите [ ]'s.Этот запрос возвращает только ОДНУ строку.Вот так...
id parent
7 3
select * from myset
where lft < :lftOfCurrent and rgt > :lftOfCurrent
order lft desc
limit 1
Вы могли бы использовать max, а не order / limit, и вам может понадобиться другое ключевое слово, чтобы ограничить результаты одной строкой в зависимости от вашей базы данных.Между , а не < и > сработало бы, если бы ваша база данных возвращала эксклюзивный набор, чего не делает MySQL.
SELECT parent.name
FROM myset AS node, myset AS parent
WHERE parent.lft < node.lft
AND parent.rgt > node.rgt
AND node.id = {YOUR CATEGORY ID}
ORDER BY ( parent.rgt - parent.lft ) ASC LIMIT 1;
Все предки возвращаются
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt;
Итак, прямой родитель - это предок с наименьшей разницей между lft и rgt.
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt
ORDER BY (rgt-lft)
LIMIT 1
Код из spankmaster79 не был полностью неправильным.Я изменил его код, и это сработало.
SELECT parent . * FROM Nested_Category AS node, Nested_Category AS parent
enter code hereWHERE node.leftSide
BETWEEN parent.leftSide
AND parent.rightSide
AND node.id ='Enter the Node ID'
ORDER BY (
parent.rightSide - parent.leftSide
)
LIMIT 1 , 1