Выбор узла в модели вложенного множества через неуникальное имя - PullRequest
2 голосов
/ 27 сентября 2010

Я пытаюсь управлять поиском узла в таблице модели вложенного набора , но не через уникальный идентификатор, а через имя (строка) и другие узлы. внутри дерева у разных родителей можно назвать одинаково.

До сих пор я использовал уникальный идентификатор для получения узлов во вложенных наборах:

SELECT
     node.name, node.lft, node.rgt
FROM tbl AS parent, tbl AS node
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.id = '{$node_id}'
GROUP BY node.id

Пытаясь расширить этот метод для более общего способа извлечения узла по его имени, я придумал запрос, содержащий столько же предложений HAVING, сколько и глубину извлекаемого узла, проверив имя узла и его глубину:

SELECT
     node.name, node.lft, node.rgt, COUNT(node.id) AS depth
FROM tbl AS parent, tbl AS node
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.id
HAVING
     (node.name = 'myParentName' AND depth = 1)
     OR
     (node.name = 'myParent2Name' AND depth = 2)
     OR
     ...
 # and so on

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

Пример:

ARTICLES
   |
   +--PHP
   |   +--the-origins
   |   +--syntax
   +--JS
       +--history
       +--syntax

В этом случае приведенный выше запрос вернет либо ARTICLES / PHP / синтаксис, либо ARTICLES / JS / синтаксис: узел «синтаксис» с глубиной 3, в действительности, находится либо под узлом PHP, либо под узлом JS. Есть ли эффективный путь, чтобы пройти, чтобы решить эту проблему?

1 Ответ

3 голосов
/ 28 сентября 2010

Я не совсем уверен, что вы пытаетесь сделать здесь.Вы пытаетесь получить доступ к узлу с путем ARTICLES/PHP/syntax?Если это так, то вам нужно будет выполнить самостоятельное объединение для каждого родительского уровня:

SELECT n0.*
FROM tbl AS n0
JOIN tbl AS n1 ON n0.lft BETWEEN n1.lft+1 AND n1.rgt
JOIN tbl AS n2 ON n1.lft BETWEEN n2.lft+1 AND n2.rgt
WHERE n0.name='syntax' AND n1.name='PHP' AND n2.name='ARTICLES'

Комментарии ETA: выполнение совпадений direct-child во вложенном множестве не очень весело.Вы должны попытаться выбрать промежуточную родительскую строку между каждой объединенной строкой.Это строка, которой вы не хотите существовать, поэтому вы затем инвертируете это условие с нулевым левым соединением.например ::

SELECT n0.*
FROM tbl AS n0
JOIN tbl AS n1 ON n0.lft BETWEEN n1.lft+1 AND n1.rgt
JOIN tbl AS n2 ON n1.lft BETWEEN n2.lft+1 AND n2.rgt
LEFT JOIN tbl AS nn1 ON nn1.lft BETWEEN n1.lft+1 AND n0.lft-1
LEFT JOIN tbl AS nn2 ON nn2.lft BETWEEN n2.lft+1 AND n1.lft-1
WHERE nn1.lft IS NULL AND nn2.lft IS NULL
AND n0.name='syntax' AND n1.name='PHP' AND n2.name='ARTICLES'
...