使用 MySQL 从树中选择记录
注意:在阅读所有这些附加内容之前,您可能需要跳到底部阅读实际问题。
我正在为 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 )查找与别名“two_action”匹配的所有记录;然后循环遍历结果并查找与最后结果的父 id 匹配且别名为“one_test_controller”的所有记录。然后重复直到parent_id = 0。
它可以工作,但显然多个递归SQL查询并不理想,是否有一个神奇的SQL查询可以帮助我解决这个问题?或者我认为这是它能得到的最好的结果是正确的吗?
Note: You might want to skip to the bottom to read the actual question before reading all this additional stuff.
I'm working on a ACL implementation for CakePHP. Mainly cause I'm trying to decouple it from AuthComponeny so I can use Authsome for my projects. I have the theory of implementation down but I've hit a little stumbling block.
Obviously I want to keep the number of database queries down to a minimum. So I'm asking here on the off chance that this is possible (I seriously doubt it is.)
Assuming a table structure like this:
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
And a few records to test (controllers is the root node and I might get the lft and rght values wrong):
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
And two test paths:
$test1 = '/controllers/one_test_controller/two_action';
$test2 = '/controllers/two_test_controller/two_action';
Giving these results, returning an array of ids from most relevant to least relevant:
// Result 1
array(
0 => 4,
1 => 2,
2 => 1
)
// Result 2
array(
0 => 7,
1 => 5,
2 => 1
)
What I'm currently doing is explode()ing the path into and array, (using $test1 for this example) first finding all records that match the alias "two_action"; then looping through the results and finding all records that match the parent id's of the last result and have the alias of "one_test_controller". Then repeat until parent_id = 0.
It works but obviously multiple recursive SQL queries are not ideal, is there a magic SQL query that can help me with this? Or am I right in assuming that this is the best it can get?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯?您已经获得了通过使用邻接树一次性解析路径来获取数据的结构。
但是,如果不存储完整路径/需要唯一的节点名称,则无法从下往上搜索。考虑一下 - 在您的两个测试用例中,您都从“two_action”开始,但正在寻找 2 个不同的叶子。如果您将整个路径存储在表中(或者可以通过查询中的 id 引用节点),那么...
或使用 ids:
或者,您可以编写一个查询来返回具有特定节点别名的每个可能路径 - 但是这也不会很有效......
(并且很容易从parent_ids重建lft和rght)
eh? You've already got the structure to fetch the data by parsing the path in a single pass with the adjacency tree.
However without storing the full path / requiring unique node names, you can't search from the bottom up. Consider - in both your test cases you're starting with 'two_action' but looking for 2 different leafs. If you store the entire path in the table (or can reference the nodes by id from your query) then....
or using ids:
Alternatively, you could write a query to return every possible path which has a specific node alias - but that's not going to be very efficient either....
(and its easy enought to rebuild lft and rght from the parent_ids)