Вложенные наборы MySQL - Как найти родительский узел?

StackOverflow https://stackoverflow.com/questions/1602536

Вопрос

У меня есть ваша обычная настройка типа иерархии вложенного набора со следующими столбцами:

имя таблицы:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top