(注意:此答案中的查询现已更新,以包括添加到问题中的列名。)
获得该结果集的一种方法是使用LEFT JOIN
操作(在 caluse 中带有适当的谓词ON
)来代替所有这些NATURAL JOIN
操作。
(我只是在猜测 引用的列名NATURAL JOIN
。为了破译这一点,我们需要检查每个表定义以获取所有列的列表,然后找到所有匹配的列名找出 MySQL 使用哪些列来执行这些内部连接操作。)
根据查询文本中提供的少量信息,这是我将采取的方法(再次,只是猜测每个 ON 子句中引用的名称):
SELECT p.PrivilageName
, IF(u.UserID IS NOT NULL,'true','false') AS hasrights
FROM `privileges` p
LEFT
JOIN groupprivileges g
ON g.PrivilegeID = p.PrivilegeID
LEFT
JOIN usermemberships m
ON m.GroupId = g.GroupID
LEFT
JOIN users u
ON u.UserID = g.UserID
AND u.UserID = 2
取决于这些表中的基数(即授予两个不同组的“AddBuilding”权限,一个是用户的成员,另一个不是......)
并取决于您是否要避免返回任何“重复”PrivilageName
值(具有“true”或“false”的多行,或每个 PrivilageName 具有“true”和“false”的行),并取决于您希望如何结果集已排序(即,您是否希望首先列出所有“真实”权限?)...
那么这个查询在返回的结果集中更具确定性,它只会返回每个 PrivilageName 一次。这个结果集似乎更适合回答用户是否有特权的问题。
SELECT p.PrivilageName
, MAX(IF(u.UserID IS NOT NULL,'true','false')) AS hasrights
FROM `privileges` p
LEFT
JOIN groupprivileges g
ON g.PrivilegeID = p.PrivilegeID
LEFT
JOIN usermemberships m
ON m.GroupId = g.GroupID
LEFT
JOIN users u
ON u.UserID = g.UserID
AND u.UserID = 2
GROUP BY p.PrivilageName
ORDER BY hasrights DESC, p.PrivilageName ASC
(就个人而言,我会省略 ORDER BY,并让结果按 PrivilageName 排序,但使用 ORDER BY,这更好地匹配问题中指定的结果集。)
当然,这不是获得结果集的唯一方法,但它可能是最有效的(给定合适的索引)。
就个人而言,我从不使用NATURAL JOIN
. (我想查看语句中的谓词,如果有人将具有匹配名称的列添加到我的查询中的一个表中,我不希望我的任何查询“中断”。(实际上,考虑一下,我不能使用 NATURAL JOIN 因为id
通常是我几乎所有表的主键列的名称......外键列通常被命名referencedtable_id
。)但即使我确实以我可以使用的方式命名列 NATURAL JOIN ,我认为潜在的缺点超过了任何优点。
但是,类似下面的陈述可能会起作用。(我说“可能”是因为我没有使用这样的语法的任何经验......我从不使用自然连接,而且我总是更喜欢左连接而不是右连接。如果我店里有人带着这个来找我,我会给他们上面的语句。但我不想给你留下 aNATURAL JOIN
不能用于返回指定结果集的印象。你指定的结果集可能会被这样的语句返回:
SELECT
PrivilageName,
MAX(IF(UserID=2,'false','true')) AS hasrights
FROM
users
NATURAL RIGHT JOIN usermemberships
NATURAL RIGHT JOIN groupprivileges
NATURAL RIGHT JOIN `privileges`
GROUP BY PrivilageName