Php 用MySQL从树中选择记录

Php 用MySQL从树中选择记录,php,mysql,tree,acl,Php,Mysql,Tree,Acl,注意:在阅读所有这些附加内容之前,您可能希望跳到底部阅读实际问题 我正在为CakePHP开发一个ACL实现。主要原因是我正在尝试将它与AuthComponeny解耦,以便在我的项目中使用Authsome。我有实现的理论,但我遇到了一个小障碍 显然,我希望将数据库查询的数量降到最低。所以我在这里提出这个问题,我很怀疑这是可能的 假设表结构如下所示: id - int(10), auto_increment, primary_key, not null parent_id - int(10), nu

注意:在阅读所有这些附加内容之前,您可能希望跳到底部阅读实际问题

我正在为CakePHP开发一个ACL实现。主要原因是我正在尝试将它与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
测试控制器的一些记录是根节点,我可能会得到错误的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';
给出这些结果,返回从最相关到最不相关的ID数组:

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

// Result 2
array(
    0 => 7,
    1 => 5,
    2 => 1
)
我目前正在做的是将路径分解为和数组,在本例中使用$test1首先查找与alias two_操作匹配的所有记录;然后遍历结果并查找与上一个结果的父id匹配且别名为one_test_controller的所有记录。然后重复,直到父项id=0


它可以工作,但显然多个递归SQL查询并不理想,是否有一个神奇的SQL查询可以帮助我做到这一点?或者我认为这是它能得到的最好的结果,这是正确的吗?您已经获得了通过使用邻接树在单个过程中解析路径来获取数据的结构

但是,如果不存储完整路径/需要唯一的节点名称,则无法从下至上进行搜索。在两个测试案例中,你从“两个动作”开始,寻找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;
或使用ID:

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;
或者,您可以编写一个查询来返回具有特定节点别名的每个可能路径,但这也不是很有效

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;

从父ID重建lft和rght很容易,谢谢,我接受。不幸的是,我无法修改该表。它必须与CakePHPs shell脚本生成的模式兼容。