MySQL вложенные наборы - как найти родителя узла?

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

имя таблицы:

myset

столбцы:

id, name, lft, rgt

кто-нибудь знает запрос для определения родитель узла?

Я прочитал пару мест, которые удобно также иметь ид_родительского_объекта столбец в вашей таблице, чтобы отслеживать это, но он кажется избыточным, и кажется, что он может выйти из синхронизации с вложенным набором если запрос был неправильно выполнен при добавлении/удалении / перемещении чего-либо в наборе.

8 ответов


посмотреть этот вопрос. Он похож на ваш. Я отправил туда запрос, который вам может понадобиться.

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, используйте LIMIT для 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 не понимала верхнюю команду. Вместо этого мне пришлось использовать 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

очевидно, измените материал в [ ], чтобы удовлетворить ваши потребности. Также удалите [ ]. Этот запрос возвращает только одну строку. Вот так...

id  parent
7   3

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

select * from myset
  where lft < :lftOfCurrent and rgt > :lftOfCurrent
  order lft desc
  limit 1

вы можете использовать max, а не order/ limit, и вам может понадобиться другое ключевое слово, чтобы ограничить результаты одной строкой в зависимости от вашей базы данных. Между, а не будет работать, если ваша база данных возвращает эксклюзивный набор, который MySQL не делает.


код от 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