我承认我对SQL(使用mySQL)的了解远远超出了数据库管理所需的标准查询,而且我的大部分数据操作都是通过php完成的。
我一直热衷于改变这一点,并且直到现在都很享受成功,如果有人可以告诉我如何在包含'parent','child'的标准表上创建继承查询的存储过程,我将不胜感激。字段,内部连接在权限表上。
作为样本数据(用于演示目的):
parent child
------------------------
admin moderator
member guest
super_admin admin
moderator member
moderator move_post
----------------------
super_admin create_forum
admin move_forum
guest view_post
member create_post
member edit_post
然后我会在组名称(例如'admin')上调用该过程以返回其权限数组('move_forum','view_post','create_post',edit_post')。我不知道我是否需要迭代或递归(我读过一些关于mySQL不支持这个的东西?),但欢迎任何建议。
(N.B。我选择使用权限作为具有TRUE / FALSE检查的字段,因为我打算将其他字段附加到每个权限,例如说明)。
答案 0 :(得分:1)
如果您正在查看树层次结构,那么嵌套集模型可以很好地工作,但涉及继承表结构的重大更改。
如果您正在实施任意有向图(例如,您有一个“作者”个人资料可以发布文章但不能发表适度评论,而“主持人”个人资料可以审核评论但不能发布文章)我想寻找其他解决方案。
一种可能性是放弃继承并手动设置每个组的权限。
另一种可能性是使用继承表来存储直接和间接继承(即,一个节点将使用“直接”关系与其所有子节点相关,以及使用“间接”关系的所有子节点)。每当您更改其中一个直接关系时,此策略都要求您重新创建表中的所有间接关系(这可以通过使用简单的INSERT SELECT
来完成),但其优点是只需要一个连接即可访问所有后代。
基本理念是:
CREATE TABLE group_inherit (
parent INT NOT NULL,
child INT NOT NULL,
distance INT NOT NULL,
PRIMARY KEY (parent,child)
);
/* Clean up indirect relations */
DELETE FROM group_inherit WHERE distance <> 0;
/* Repeat this for each D > 0 until the maximum distance is reached */
INSERT IGNORE INTO (parent, child, distance)
SELECT fst.parent, snd.child, D
FROM group_inherit fst
INNER JOIN group_inherit snd ON snd.parent = fst.child
WHERE fst.distance = 0 AND snd.distance = D - 1;
/* Select all permissions for a user type */
SELECT perm.*
FROM group_permissions perm
INNER JOIN group_inherit ON perm.moderator = child
WHERE parent = ?
应该完成距离循环,直到没有更多距离为D-1的元素可用,这可以使用选择查询完成,或者,如果有的话,可以使用有关插入了多少行的元信息。
答案 1 :(得分:0)
您需要按照文档here创建嵌套的左右键,并将其用于继承查询。
答案 2 :(得分:0)
快速刺了一下,所以建议你仔细检查结果!
完整的脚本:http://pastie.org/1213230
-- TABLES
drop table if exists roles;
create table roles
(
role_id tinyint unsigned not null primary key,
name varchar(255) unique not null,
parent_role_id tinyint unsigned,
key (parent_role_id)
)
engine=innodb;
drop table if exists actions;
create table actions
(
action_id smallint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
drop table if exists role_actions;
create table role_actions
(
role_id tinyint unsigned not null,
action_id smallint unsigned not null,
primary key (role_id, action_id)
)
engine=innodb;
-- STORED PROCEDURES
drop procedure if exists list_role_actions;
delimiter #
create procedure list_role_actions
(
in p_role_id tinyint unsigned
)
proc_main:begin
declare done tinyint unsigned default 0;
declare dpth smallint unsigned default 0;
drop temporary table if exists hier;
drop temporary table if exists tmp;
create temporary table hier(
parent_role_id tinyint unsigned,
role_id tinyint unsigned,
depth smallint unsigned default 0
)engine = memory;
insert into hier select parent_role_id, role_id, dpth from roles where role_id = p_role_id;
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
create temporary table tmp engine=memory select * from hier;
while done <> 1 do
if exists( select 1 from roles r inner join hier on r.parent_role_id = hier.role_id and hier.depth = dpth) then
insert into hier
select r.parent_role_id, r.role_id, dpth + 1 from roles r
inner join tmp on r.parent_role_id = tmp.role_id and tmp.depth = dpth;
set dpth = dpth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = dpth;
else
set done = 1;
end if;
end while;
/*
select
r.*,
p.name as parent_role_name,
hier.depth
from
hier
inner join roles r on hier.role_id = r.role_id
inner join roles p on hier.parent_role_id = p.role_id
order by
hier.depth, hier.role_id;
*/
select
ra.*,
r.name as role_name,
a.name as action_name
from
role_actions ra
inner join hier h on h.role_id = ra.role_id
inner join actions a on ra.action_id = a.action_id
inner join roles r on ra.role_id = r.role_id
order by
ra.role_id desc;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end proc_main #
delimiter ;
-- TEST DATA
insert into roles values
(0,'guest',1),(1,'member',2),(2,'moderator',3),(3,'admin',99),(99,'super admin',null);
insert into actions (name) values
('view post'), ('create post'), ('edit post'), ('move forum'), ('create forum');
insert into role_actions values
-- guest
(0,1),
-- member
(1,2),
-- moderator
(2,3),
-- admin
(3,4),
-- super admin
(99,5);
-- TESTING
call list_role_actions(0);
call list_role_actions(1);
call list_role_actions(2);
call list_role_actions(3);
call list_role_actions(99);
答案 3 :(得分:0)
如果层次结构只是意味着更高的up =更多允许,那么为角色提供评级会更容易,更高,更强大。 然后给予行动评级。评级等于或高于操作的组中的任何用户都可以执行操作。