使用 1:1 链接表和 CTE(例如,对用户和组的权限)查找与其他关联的 SQL 行
Find SQL rows associated to other using 1:1 linking tables and CTE (eg. permissions on users and groups)
问题
我需要确定用户 U
是否可以根据存储在 MySQL tables(在 MariaDB 10.2 上)的权限使用以下内容访问实体 E
规则:
- 可以将权限授予用户和组。
- permissions are only allow: 一个实体和一个user/group之间的关系的存在意味着它(用户或组)被允许访问该实体.
- 组成员资格:一个用户可以是一个或多个组的一部分。
- 组继承:一个组可以有一个父组,父组的权限适用于子组。
tables 已经到位,我理解我的问题的方式归结为:
“在用户行 U
和实体行 E
之间是否存在 link(通过任何可能的路径)?”
因为 table 没有图表(请参阅下面的详细信息)并且因为组继承我想我可以在这里使用 Common Table 表达式(我不熟悉),递归(对我来说更糟)。
我的尝试
所以我构建了以下 SQL 查询以支持直接实体用户津贴(第一个 CTE:cte_entities_allowed_to_users
)
SET @TEST_EID = 302;
SET @TEST_UID = 103;
WITH
cte_entities_allowed_to_users AS (
SELECT
DISTINCT
entities.eid,
entity_user_access.uid
FROM
entity_user_access
JOIN entities
ON entity_user_access.eid = entities.eid
)
SELECT
COUNT(*)
FROM
cte_entities_allowed_to_users
WHERE
cte_entities_allowed_to_users.eid = @TEST_EID
AND cte_entities_allowed_to_users.uid = @TEST_UID
并且还构建了以下其他 CTE:
cte_groups_of_users AS (
SELECT
DISTINCT
users.uid,
groups.gid
FROM
groups
JOIN group_members
ON group_members.gid = groups.gid
JOIN users
ON users.uid = group_members.uid
)
,
cte_entities_allowed_to_groups AS (
SELECT
DISTINCT
entities.eid,
entity_group_access.gid
FROM
entity_group_access
JOIN entities
ON entity_group_access.eid = entities.eid
)
我奋斗的地方
但我不确定:
- 如何一起使用它们
- 也不知道如何构建另一个 CTE(主要是使用
group_of_groups
table)
- CTE 是否是解决此类问题的方法
我所期望的(“真相table”)
对于以下 @TEST_EID
和 @TEST_UID
对,这里是 SELECT(COUNT(*)
字段)的预期返回值:
@TEST_EID
@TEST_UID
Return
Why
301
101
≥1
entity_user_access
has a (301,101)
row
301
102
≥1
entity_user_access
has a (301,102)
row
301
103
=0
302
101
=0
302
102
≥1
entity_group_access
has a (302,201)
row and group_members
has a (201,102)
row
302
103
≥1
entity_user_access
has a (302,103)
row
303
101
=0
303
102
≥1
(303,201)
row in entity_group_access
and group_members
has a (201,102)
row
303
103
≥1
entity_user_access
has a (303,103)
row
304
101
≥1
(304,205)
row in entity_group_access
and group_of_groups
has a(204,205)
row and group_members
has a (204,101)
row
304
102
≥1
(304,201)
row in entity_group_access
and group_members
has a (201,102)
row
304
103
≥1
(304,205)
row in entity_group_access
and group_of_groups
has a(202,205)
row and group_members
has a (202,103)
row
附件 1/1:Table详细信息
关系:
[users]───────────────[group_members]─────[groups]──┐
│ │ │ │
│ │ └──[group_of_groups]
[entity_user_access] [entity_group_access]
│ │
└────────┐ ┌─────────┘
│ │
[entities]
一些示例数据集:
users
table:
uid
uname
101
Alice
102
Bob
103
Charlie
groups
table:
gid
gname
201
Administrators
202
Users
203
Operators
204
Guests
205
X-Mas event
entities
table:
eid
ename
301
Foo
302
Bar
303
Qux
304
Snow
entity_user_access
table:
eid
uid
301
101
301
102
302
103
303
103
entity_group_access
table:
eid
gid
301
201
302
201
303
201
304
201
302
203
304
205
group_members
table:
gid
uid
Comment (not part of data)
201
102
Bob is an admin
203
102
Bob is also an operator
202
103
Charlie is an user
204
101
Alice is a guest
group_of_groups
table:
gid
parent_gid
Comment (not part of data)
201
203
Admins (201) are Operators (203)
202
205
Users (202) are in the X-Mas event group (205)
204
205
Guests (204) are in the X-Mas event group (205)
完整 SQL:
-- Structure
CREATE TABLE `users` (
`uid` INT(11) NOT NULL,
`uname` TINYTEXT NOT NULL,
PRIMARY KEY (`uid`)
);
CREATE TABLE `groups` (
`gid` INT(11) NOT NULL,
`gname` TINYTEXT NOT NULL,
PRIMARY KEY (`gid`)
);
CREATE TABLE `entities` (
`eid` INT(11) NOT NULL,
`ename` TINYTEXT NOT NULL,
PRIMARY KEY (`eid`)
);
CREATE TABLE `entity_user_access` (
`eid` INT(11) NOT NULL,
`uid` INT(11) NOT NULL,
PRIMARY KEY (`eid`, `uid`),
CONSTRAINT `FK_eua_entity` FOREIGN KEY (`eid`) REFERENCES `entities` (`eid`),
CONSTRAINT `FK_eua_user` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`)
);
CREATE TABLE `entity_group_access` (
`eid` INT(11) NOT NULL,
`gid` INT(11) NOT NULL,
PRIMARY KEY (`eid`, `gid`),
CONSTRAINT `FK_ega_entity` FOREIGN KEY (`eid`) REFERENCES `entities` (`eid`),
CONSTRAINT `FK_ega_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`)
);
CREATE TABLE `group_members` (
`gid` INT(11) NOT NULL,
`uid` INT(11) NOT NULL,
PRIMARY KEY (`gid`, `uid`),
CONSTRAINT `FK_gm_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`),
CONSTRAINT `FK_gm_user` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`)
);
CREATE TABLE `group_of_groups` (
`gid` INT(11) NOT NULL,
`parent_gid` INT(11) NOT NULL,
PRIMARY KEY (`gid`, `parent_gid`),
CONSTRAINT `FK_gog_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`),
CONSTRAINT `FK_gog_parent_group` FOREIGN KEY (`parent_gid`) REFERENCES `groups` (`gid`)
);
-- Data
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
INSERT INTO `users` VALUES
(101, 'Alice'),
(102, 'Bob'),
(103, 'Charlie');
INSERT INTO `groups` VALUES
(201, 'Administrators'),
(202, 'Users'),
(203, 'Operators'),
(204, 'Guests'),
(205, 'X-Mas event');
INSERT INTO `entities` VALUES
(301, 'Foo'),
(302, 'Bar'),
(303, 'Qux'),
(304, 'Snow');
INSERT INTO `entity_user_access` VALUES
(301, 101),
(301, 102),
(302, 103),
(303, 103);
INSERT INTO `entity_group_access` VALUES
(301, 201),
(302, 201),
(302, 203),
(303, 201),
(304, 201),
(304, 205);
INSERT INTO `group_members` VALUES
(201, 102),
(202, 103),
(203, 102),
(204, 101);
INSERT INTO `group_of_groups` VALUES
(201, 203),
(202, 205),
(204, 205);
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
CTE 只是子查询的替代品。
但是你的处理方式有点离谱
您的群组 table 需要与第一个群组具有相同的结构,因此您必须加入其他 table 群组才能获得 eid 和 uid
下一步是 UNION
结果,以便它们垂直连接
在那个工会上你 运行 你的计数查询
查看示例
SET @TEST_EID = 302;
SET @TEST_UID = 103;
SELECT COUNT(*)
FROM
( SELECT
DISTINCT
entities.eid,
entity_user_access.uid
FROM
entity_user_access
JOIN entities
ON entity_user_access.eid = entities.eid
UNION
SELECT
DISTINCT
entities.eid,
users.uid
FROM
`groups`
JOIN group_members
ON group_members.gid = groups.gid
JOIN users
ON users.uid = group_members.uid
JOIN
entity_group_access
ON groups.gid = entity_group_access.gid
JOIN entities
ON entity_group_access.eid = entities.eid) t1
WHERE eid = @TEST_EID and uid = @TEST_UID
| COUNT(*) |
| -------: |
| 1 |
db<>fiddle here
问题
我需要确定用户 U
是否可以根据存储在 MySQL tables(在 MariaDB 10.2 上)的权限使用以下内容访问实体 E
规则:
- 可以将权限授予用户和组。
- permissions are only allow: 一个实体和一个user/group之间的关系的存在意味着它(用户或组)被允许访问该实体.
- 组成员资格:一个用户可以是一个或多个组的一部分。
- 组继承:一个组可以有一个父组,父组的权限适用于子组。
tables 已经到位,我理解我的问题的方式归结为:
“在用户行 U
和实体行 E
之间是否存在 link(通过任何可能的路径)?”
因为 table 没有图表(请参阅下面的详细信息)并且因为组继承我想我可以在这里使用 Common Table 表达式(我不熟悉),递归(对我来说更糟)。
我的尝试
所以我构建了以下 SQL 查询以支持直接实体用户津贴(第一个 CTE:cte_entities_allowed_to_users
)
SET @TEST_EID = 302;
SET @TEST_UID = 103;
WITH
cte_entities_allowed_to_users AS (
SELECT
DISTINCT
entities.eid,
entity_user_access.uid
FROM
entity_user_access
JOIN entities
ON entity_user_access.eid = entities.eid
)
SELECT
COUNT(*)
FROM
cte_entities_allowed_to_users
WHERE
cte_entities_allowed_to_users.eid = @TEST_EID
AND cte_entities_allowed_to_users.uid = @TEST_UID
并且还构建了以下其他 CTE:
cte_groups_of_users AS (
SELECT
DISTINCT
users.uid,
groups.gid
FROM
groups
JOIN group_members
ON group_members.gid = groups.gid
JOIN users
ON users.uid = group_members.uid
)
,
cte_entities_allowed_to_groups AS (
SELECT
DISTINCT
entities.eid,
entity_group_access.gid
FROM
entity_group_access
JOIN entities
ON entity_group_access.eid = entities.eid
)
我奋斗的地方
但我不确定:
- 如何一起使用它们
- 也不知道如何构建另一个 CTE(主要是使用
group_of_groups
table) - CTE 是否是解决此类问题的方法
我所期望的(“真相table”)
对于以下 @TEST_EID
和 @TEST_UID
对,这里是 SELECT(COUNT(*)
字段)的预期返回值:
@TEST_EID |
@TEST_UID |
Return | Why |
---|---|---|---|
301 | 101 | ≥1 | entity_user_access has a (301,101) row |
301 | 102 | ≥1 | entity_user_access has a (301,102) row |
301 | 103 | =0 | |
302 | 101 | =0 | |
302 | 102 | ≥1 | entity_group_access has a (302,201) row and group_members has a (201,102) row |
302 | 103 | ≥1 | entity_user_access has a (302,103) row |
303 | 101 | =0 | |
303 | 102 | ≥1 | (303,201) row in entity_group_access and group_members has a (201,102) row |
303 | 103 | ≥1 | entity_user_access has a (303,103) row |
304 | 101 | ≥1 | (304,205) row in entity_group_access and group_of_groups has a(204,205) row and group_members has a (204,101) row |
304 | 102 | ≥1 | (304,201) row in entity_group_access and group_members has a (201,102) row |
304 | 103 | ≥1 | (304,205) row in entity_group_access and group_of_groups has a(202,205) row and group_members has a (202,103) row |
附件 1/1:Table详细信息
关系:
[users]───────────────[group_members]─────[groups]──┐
│ │ │ │
│ │ └──[group_of_groups]
[entity_user_access] [entity_group_access]
│ │
└────────┐ ┌─────────┘
│ │
[entities]
一些示例数据集:
users
table:
uid | uname |
---|---|
101 | Alice |
102 | Bob |
103 | Charlie |
groups
table:
gid | gname |
---|---|
201 | Administrators |
202 | Users |
203 | Operators |
204 | Guests |
205 | X-Mas event |
entities
table:
eid | ename |
---|---|
301 | Foo |
302 | Bar |
303 | Qux |
304 | Snow |
entity_user_access
table:
eid | uid |
---|---|
301 | 101 |
301 | 102 |
302 | 103 |
303 | 103 |
entity_group_access
table:
eid | gid |
---|---|
301 | 201 |
302 | 201 |
303 | 201 |
304 | 201 |
302 | 203 |
304 | 205 |
group_members
table:
gid | uid | Comment (not part of data) |
---|---|---|
201 | 102 | Bob is an admin |
203 | 102 | Bob is also an operator |
202 | 103 | Charlie is an user |
204 | 101 | Alice is a guest |
group_of_groups
table:
gid | parent_gid | Comment (not part of data) |
---|---|---|
201 | 203 | Admins (201) are Operators (203) |
202 | 205 | Users (202) are in the X-Mas event group (205) |
204 | 205 | Guests (204) are in the X-Mas event group (205) |
完整 SQL:
-- Structure
CREATE TABLE `users` (
`uid` INT(11) NOT NULL,
`uname` TINYTEXT NOT NULL,
PRIMARY KEY (`uid`)
);
CREATE TABLE `groups` (
`gid` INT(11) NOT NULL,
`gname` TINYTEXT NOT NULL,
PRIMARY KEY (`gid`)
);
CREATE TABLE `entities` (
`eid` INT(11) NOT NULL,
`ename` TINYTEXT NOT NULL,
PRIMARY KEY (`eid`)
);
CREATE TABLE `entity_user_access` (
`eid` INT(11) NOT NULL,
`uid` INT(11) NOT NULL,
PRIMARY KEY (`eid`, `uid`),
CONSTRAINT `FK_eua_entity` FOREIGN KEY (`eid`) REFERENCES `entities` (`eid`),
CONSTRAINT `FK_eua_user` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`)
);
CREATE TABLE `entity_group_access` (
`eid` INT(11) NOT NULL,
`gid` INT(11) NOT NULL,
PRIMARY KEY (`eid`, `gid`),
CONSTRAINT `FK_ega_entity` FOREIGN KEY (`eid`) REFERENCES `entities` (`eid`),
CONSTRAINT `FK_ega_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`)
);
CREATE TABLE `group_members` (
`gid` INT(11) NOT NULL,
`uid` INT(11) NOT NULL,
PRIMARY KEY (`gid`, `uid`),
CONSTRAINT `FK_gm_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`),
CONSTRAINT `FK_gm_user` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`)
);
CREATE TABLE `group_of_groups` (
`gid` INT(11) NOT NULL,
`parent_gid` INT(11) NOT NULL,
PRIMARY KEY (`gid`, `parent_gid`),
CONSTRAINT `FK_gog_group` FOREIGN KEY (`gid`) REFERENCES `groups` (`gid`),
CONSTRAINT `FK_gog_parent_group` FOREIGN KEY (`parent_gid`) REFERENCES `groups` (`gid`)
);
-- Data
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
INSERT INTO `users` VALUES
(101, 'Alice'),
(102, 'Bob'),
(103, 'Charlie');
INSERT INTO `groups` VALUES
(201, 'Administrators'),
(202, 'Users'),
(203, 'Operators'),
(204, 'Guests'),
(205, 'X-Mas event');
INSERT INTO `entities` VALUES
(301, 'Foo'),
(302, 'Bar'),
(303, 'Qux'),
(304, 'Snow');
INSERT INTO `entity_user_access` VALUES
(301, 101),
(301, 102),
(302, 103),
(303, 103);
INSERT INTO `entity_group_access` VALUES
(301, 201),
(302, 201),
(302, 203),
(303, 201),
(304, 201),
(304, 205);
INSERT INTO `group_members` VALUES
(201, 102),
(202, 103),
(203, 102),
(204, 101);
INSERT INTO `group_of_groups` VALUES
(201, 203),
(202, 205),
(204, 205);
/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
CTE 只是子查询的替代品。
但是你的处理方式有点离谱
您的群组 table 需要与第一个群组具有相同的结构,因此您必须加入其他 table 群组才能获得 eid 和 uid
下一步是 UNION
结果,以便它们垂直连接
在那个工会上你 运行 你的计数查询
查看示例
SET @TEST_EID = 302; SET @TEST_UID = 103;
SELECT COUNT(*) FROM ( SELECT DISTINCT entities.eid, entity_user_access.uid FROM entity_user_access JOIN entities ON entity_user_access.eid = entities.eid UNION SELECT DISTINCT entities.eid, users.uid FROM `groups` JOIN group_members ON group_members.gid = groups.gid JOIN users ON users.uid = group_members.uid JOIN entity_group_access ON groups.gid = entity_group_access.gid JOIN entities ON entity_group_access.eid = entities.eid) t1 WHERE eid = @TEST_EID and uid = @TEST_UID
| COUNT(*) | | -------: | | 1 |
db<>fiddle here