我只需要解决这个问题的更一般情况,但在 SQL Server 中。原则可能是相似的。
SetX
|-- Child1
|-- Child2
|-- Child4
SetY
|-- Child1
|-- Child3
ParentA -- has the children defined by SetX
|-- Child1
|-- Child2
|-- Child4
ParentB -- has the children defined by SetY
|-- Child1
|-- Child3
ParentC -- does not match any of the sets
|-- Child1
|-- Child2
|-- Child3
|-- Child4
M 问题是围绕系统的用户(父母),他们在系统中被分配的角色(孩子),以及适合用户的工作描述(集合)。
我解决它的方法是使用位掩码。每个孩子都被分配了一个唯一的 2^n 位掩码。集合的成员关系就是用户的位掩码和等于集合的位掩码和。
当有很多孩子并且位掩码有溢出的危险时,您可以使用 bigint 位掩码或多个位掩码(确保将低阶位掩码设置为零)。
这是一个用 T-SQL 编写的示例 - 很确定它会很容易转换为 MySQL(如果有人想在他们自己的答案中这样做,我很高兴)。
declare @users table (
name varchar(10)
)
declare @skills table (
name varchar(20)
, id int identity (0, 1)
, bitmask bigint
)
declare @usersWithSkills table (
userName varchar(10)
, skillName varchar(20)
)
declare @groups table (
name varchar(20)
, bitmask bigint
)
declare @skillsInGroups table (
groupName varchar(10)
, skillName varchar(20)
)
insert @users (name)
values ('Pat')
, ('Oprah')
, ('Millie')
, ('Bert')
insert @skills (name)
values ('Latin')
, ('Icelandic')
, ('Physics')
insert @groups (name)
values ('polyglot')
, ('modern')
, ('omniscient')
insert @skillsInGroups (groupName, skillName)
values ('polyglot', 'Latin')
, ('polyglot', 'Icelandic')
, ('modern', 'Physics')
, ('modern', 'Icelandic')
, ('omniscient', 'Latin')
, ('omniscient', 'Icelandic')
, ('omniscient', 'Physics')
insert @usersWithSkills (userName, skillName)
values ('Pat', 'Latin')
, ('Pat', 'Icelandic')
, ('Oprah', 'Latin')
, ('Oprah', 'Icelandic')
, ('Oprah', 'Physics')
, ('Millie', 'Icelandic')
, ('Millie', 'Physics')
, ('Bert', 'Latin')
-- give each skill a bitmask value
update @skills
set bitmask = power(2, id)
-- set the total bitmask values for each group
update g1
set g1.bitmask = t.sum_ind
from @groups g1
inner join (
select g.name, sum_ind = sum(r.bitmask)
from @groups g
inner join @skillsInGroups rg
on rg.groupName = g.name
inner join @skills r
on r.name = rg.skillName
group by g.name
) t
on t.name = g1.name
select u1.userName, groupName = g.name
from (
select userName = u.name
, bitmask_total = sum(r.bitmask)
from @users u
inner join @usersWithSkills uir
on uir.userName = u.name
inner join @skills r
on r.name = uir.skillName
group by u.name
) u1
left join @groups g
on g.bitmask = u1.bitmask_total
我从中得到的结果是
userName groupName
---------- --------------------
Bert NULL
Millie modern
Oprah omniscient
Pat polyglot
(4 rows affected)