我创建了以下基于角色的访问数据库模式,该模式能够保存角色,操作和类型。角色可以对类型执行特定操作。与用户或类型的连接在这里并不重要,因为这将是特定于应用程序的。这三个表中的每一个都可以拥有他们想要的父母。
目前我正在努力解决一个问题,该问题从role_operation_type table
输出所有可能的组合。
每个角色都应该继承祖先的每个类型的权限,这些权限可以是多个。在我看来,我需要三个嵌套递归查询,或者有更快的方法来实现它?
我的目的是将该查询放在视图中,并在用户请求对类型进行操作时选择所需的值。
以下是数据库架构:
CREATE TABLE IF NOT EXISTS `role` (
`id` INTEGER PRIMARY KEY,
`name` VARCHAR NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS `role_role` (
`role_id` INTEGER NOT NULL REFERENCES `role`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
`parent_role_id` INTEGER NOT NULL REFERENCES `role`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT role_uq UNIQUE (`role_id`, `parent_role_id`),
CONSTRAINT role_chk CHECK(`role_id` != `parent_role_id`)
);
CREATE TABLE IF NOT EXISTS `operation` (
`id` INTEGER PRIMARY KEY,
`name` VARCHAR NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS `operation_operation` (
`operation_id` INTEGER NOT NULL REFERENCES `operation`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
`parent_operation_id` INTEGER NOT NULL REFERENCES `operation`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT operation_uq UNIQUE (`operation_id`, `parent_operation_id`),
CONSTRAINT operation_chk CHECK(`operation_id` != `parent_operation_id`)
);
CREATE TABLE IF NOT EXISTS `type` (
`id` INTEGER PRIMARY KEY,
`name` VARCHAR NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS `type_type` (
`type_id` INTEGER NOT NULL REFERENCES `type`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
`parent_type_id` INTEGER NOT NULL REFERENCES `type`(`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT type_uq UNIQUE (`type_id`, `parent_type_id`),
CONSTRAINT type_chk CHECK(`type_id` != `parent_type_id`)
);
CREATE TABLE IF NOT EXISTS `role_operation_type` (
`role_id` INTEGER NOT NULL REFERENCES `role`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
`operation_id` INTEGER NOT NULL REFERENCES `operation`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
`type_id` INTEGER NOT NULL REFERENCES `type`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT role_id_operation_id_type_id_uq UNIQUE (`role_id`, `operation_id`, `type_id`)
);
CREATE VIEW IF NOT EXISTS role_role_recursive_view AS
WITH RECURSIVE p(role_id, r, parent_role_id) AS (
SELECT ROLE.id, ROLE.id, role_role.parent_role_id
FROM ROLE
INNER JOIN role_role ON ROLE.id = role_role.role_id
UNION
SELECT p.r, p.role_id, role_role.parent_role_id
FROM p
INNER JOIN role_role ON p.parent_role_id = role_role.role_id
WHERE p.r != role_role.parent_role_id
)
SELECT p.role_id, p.parent_role_id FROM p ORDER BY role_id;
CREATE VIEW IF NOT EXISTS operation_operation_recursive_view AS
WITH RECURSIVE o(operation_id, o, parent_operation_id) AS (
SELECT operation.id, operation.id, operation_operation.parent_operation_id
FROM operation
INNER JOIN operation_operation ON operation.id = operation_operation.operation_id
UNION
SELECT o.o, o.operation_id, operation_operation.parent_operation_id
FROM o
INNER JOIN operation_operation ON o.parent_operation_id = operation_operation.operation_id
WHERE o.o != operation_operation.parent_operation_id
)
SELECT o.operation_id, o.parent_operation_id FROM o ORDER BY operation_id;
CREATE VIEW IF NOT EXISTS type_type_recursive_view AS
WITH RECURSIVE t(type_id, t, parent_type_id) AS (
SELECT TYPE.id, TYPE.id, type_type.parent_type_id
FROM TYPE
INNER JOIN type_type ON TYPE.id = type_type.type_id
UNION
SELECT t.t, t.type_id, type_type.parent_type_id
FROM t
INNER JOIN type_type ON t.parent_type_id = type_type.type_id
WHERE t.t != type_type.parent_type_id
)
SELECT t.type_id, t.parent_type_id FROM t ORDER BY type_id;
答案 0 :(得分:1)
现在我将用一个效果很好的解决方案回答我自己的问题。这是一个递归查询,并生成每个可能的组合。这是一个递归查询,当继承级别变得更深时可能会很慢。
CREATE VIEW IF NOT EXISTS role_operation_type_recursive_view AS
WITH RECURSIVE T(role_id, operation_id, type_id) AS (
WITH RECURSIVE O(role_id, operation_id, type_id) AS (
WITH RECURSIVE R(role_id, operation_id, type_id) AS (
SELECT role_id, operation_id,type_id
FROM role_operation_type
UNION
SELECT role_role_recursive_view.role_id, R.operation_id, R.type_id
FROM R
INNER JOIN role_role_recursive_view ON R.role_id = role_role_recursive_view.parent_role_id
)
SELECT * FROM R
UNION
SELECT O.role_id,operation_operation_recursive_view.parent_operation_id ,O.type_id
FROM O
INNER JOIN operation_operation_recursive_view ON O.operation_id = operation_operation_recursive_view.operation_id
)
SELECT * FROM O
UNION
SELECT T.role_id, T.operation_id, type_type_recursive_view.type_id
FROM T
INNER JOIN type_type_recursive_view ON T.type_id = type_type_recursive_view.parent_type_id
)
SELECT * FROM T;