0

我有一个选择用户权限并添加true到它们的 SQL 查询。

SELECT
    PrivilageName,
    'true' hasrights  <-- imaginary column
FROM
    users
NATURAL JOIN usermemberships
NATURAL JOIN groupprivileges
NATURAL JOIN `privileges`
WHERE
    UserID = '2'

结果是

AddBuilding           true
RemoveBuilding        true
EditBuilding          true

我正在尝试添加具有false价值的其余特权。

AddBuilding           true
RemoveBuilding        true
EditBuilding          true
RemoveUser            false
AddUser               false

我将如何做到这一点?

编辑:表的结构:

users(UserID),
usermemberships(UserID, groupID),
groupprivileges(GroupID, PrivilegeID),
privileges(PrivilegeID, PrivilageName)

编辑:拼写错误,对不起。

4

2 回答 2

1

(注意:此答案中的查询现已更新,以包括添加到问题中的列名。)

获得该结果集的一种方法是使用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
于 2013-02-14T16:02:53.887 回答
0

您可以将 UNION 用于“连接”两个请求。

并且可能是运算符 IF() 可以帮助您。

于 2013-02-14T15:49:26.973 回答