Выбор записи из дерева с MySQL

0

Примечание.. Вы можете пропустить снизу, чтобы прочитать фактический вопрос, прежде чем читать все это.

Я работаю над реализацией ACL для CakePHP. В основном я пытаюсь отделить его от AuthComponeny, поэтому я могу использовать Authsome для своих проектов. У меня есть теория реализации, но я ударил немного камнем преткновения.

Очевидно, я хочу свести число запросов к базе данных до минимума. Поэтому я спрашиваю здесь, что это возможно (я серьезно сомневаюсь, что это так.)

Предполагая структуру таблицы следующим образом:

id - int(10), auto_increment, primary_key, not null
parent_id - int(10), null
model - varchar(255), utf8_bin, null
foreign_key - int(10), null
alias - varchar(255), utf8_bin, null,
lft - int(10), null
rght - int(10), null

И несколько записей для проверки (контроллеры - это корень node, и я могу ошибиться в значениях lft и rght):

1, null, null, null, controllers,          1,  14
2, 1,    null, null, one_test_controllers, 2,  7
3, 2,    null, null, one_action,           3,  4
4, 2,    null, null, two_action,           5,  6
5, 1,    null, null, two_test_controllers, 8,  13
6, 5,    null, null, one_action,           9,  10
7, 5,    null, null  two_action,           11, 12

И два тестовых пути:

$test1 = '/controllers/one_test_controller/two_action';
$test2 = '/controllers/two_test_controller/two_action';

Предоставление этих результатов, возвращая массив идентификаторов из наиболее релевантных для наименее релевантных:

// Result 1
array(
    0 => 4,
    1 => 2,
    2 => 1
)

// Result 2
array(
    0 => 7,
    1 => 5,
    2 => 1
)

То, что я сейчас делаю, - explode(), введя путь в и массив (используя $test1 для этого примера), сначала обнаруживает все записи, которые соответствуют псевдониму "two_action"; затем перебирает результаты и находит все записи, соответствующие родительскому идентификатору последнего результата, и имеет псевдоним "one_test_controller". Затем повторите до parent_id = 0.

Это работает, но, очевидно, несколько рекурсивных SQL-запросов не идеальны, есть ли волшебный SQL-запрос, который может мне помочь? Или я прав, полагая, что это лучшее, что он может получить?

Теги:
acl
tree

1 ответ

2
Лучший ответ

а? У вас уже есть структура для извлечения данных путем разбора пути за один проход с деревом смежности.

Однако, не сохраняя полный путь/требуя уникальных имен node, вы не можете искать снизу вверх. Подумайте - в обоих тестовых случаях вы начинаете с "two_action", но ищете 2 разных листа. Если вы сохраняете весь путь в таблице (или можете ссылаться на узлы по id из вашего запроса), то....

SELECT ancestors.*
FROM ahier ancestors,
(SELECT lft, rght
  FROM ahier ref
  WHERE ref.path='/controllers/one_test_controller/two_action') ilv
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght)
ORDER BY ancestors.lft ASC;

или используя идентификаторы:

SELECT ancestors.*
FROM ahier ancestors,
(SELECT lft, rght
  FROM ahier ref
  WHERE ref.id=4) ilv
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght)
ORDER BY ancestors.lft ASC;

В качестве альтернативы вы можете написать запрос, чтобы возвращать все возможные пути, которые имеют определенный псевдоним node, но это не будет очень эффективным....

SELECT treenum, ancestors.*
FROM ahier ancestors,
(SELECT lft, rght, id as treenum
  FROM ahier ref
  WHERE ref.alias='two_action') ilv
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght)
ORDER BY treenum, ancestors.lft ASC;

(и его достаточно легко перестроить lft и rght из parent_ids)

  • 0
    Спасибо, я приму это. К сожалению, я не могу изменить таблицу. Он должен быть совместим со схемой, созданной сценарием оболочки CakePHPs.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню