mySQL从一个表中选择另一个表中不存在的表,而不是第三个表中的子表

时间:2012-09-18 09:16:23

标签: mysql yii rbac

我正在使用Yii RBAC来控制用户对我的应用程序的访问,它包含三个mySql表;

authitem(RBAC角色项目)

authitemchild(任何属于其他角色的RBAC规则)

authitemassignment(为用户分配角色)

例如,我们可能有这样的表:

authitem:

|   name (pk)   |
 areaASuperUser
 areaACreateOnly
 areaAReadOnly
 areaAUpdateOnly
 areaADeleteOnly

 areaBSuperUser
 areaBCreateOnly
 areaBReadOnly
 areaBUpdateOnly
 areaBDeleteOnly

authitemchild

|   parent (pk)   |   child (pk)   |
 areaASuperUser    areaACreateOnly
 areaASuperUser    areaAReadOnly
 areaASuperUser    areaAUpdateOnly
 areaASuperUser    areaADeleteOnly

 areaBSuperUser    areaBCreateOnly
 areaBSuperUser    areaBReadOnly
 areaBSuperUser    areaBUpdateOnly
 areaBSuperUser    areaBDeleteOnly

auithitemassignment

|    itemname (pk)   |   userid (pk)   |
 areaASuperUser       1

在上面的场景中,id为1的用户在areaA中具有完整的CRUD访问权限。我需要的是用户不能访问的所有角色的列表,我也需要考虑他们也可以访问的任何角色的孩子。

我可以轻松获取用户无权访问的所有角色:

SELECT DISTINCT `ai`.`name`
FROM `authitem` `ai`
LEFT JOIN `authassignment` `aa`
ON `aa`.`itemname` = `ai`.`name` AND `aa`.`userid` = 1
WHERE  `aa`.`itemname` IS NULL

但是这会回来:

 |   name    |
 areaACreateOnly
 areaAReadOnly
 areaAUpdateOnly
 areaADeleteOnly

 areaBSuperUser
 areaBCreateOnly
 areaBReadOnly
 areaBUpdateOnly
 areaBDeleteOnly

因为所有areaA *角色都是areaASuperUser的子角色,所以我不想让它们返回。

非常感谢任何有关正确方向的建议或推动!

* 编辑:

感谢@SuVeRa,您的回答:

SELECT DISTINCT `ai`.`name`
FROM `authitem` `ai`
LEFT JOIN `authassignment` `aa`
ON `aa`.`itemname` = `ai`.`name` AND `aa`.`userid` = 1
WHERE  
`aa`.`itemname` IS NULL 
AND `ai`.`name` NOT IN (
    SELECT
    `aic`.`child` itemname
    FROM `authitemchild` `aic`
    JOIN `authassignment` `aa`
    ON `aa`.`itemname` = `aic`.`parent`
    WHERE `aa`.`userid` = 1
)

完全适用于上面的例子,但我只是扩展了应用程序,为儿童提供了多个级别,即

authitem:

|   name (pk)   |

 areaABSuperUser

 areaASuperUser
 areaACreateOnly
 areaAReadOnly
 areaAUpdateOnly
 areaADeleteOnly

 areaBSuperUser
 areaBCreateOnly
 areaBReadOnly
 areaBUpdateOnly
 areaBDeleteOnly

 areaCSuperUser
 areaCCreateOnly
 areaCReadOnly
 areaCUpdateOnly
 areaCDeleteOnly

authitemchild

|   parent (pk)   |   child (pk)   |
 areaABSuperUser   areaASuperUser
 areaABSuperUser   areaBSuperUser

 areaASuperUser    areaACreateOnly
 areaASuperUser    areaAReadOnly
 areaASuperUser    areaAUpdateOnly
 areaASuperUser    areaADeleteOnly

 areaBSuperUser    areaBCreateOnly
 areaBSuperUser    areaBReadOnly
 areaBSuperUser    areaBUpdateOnly
 areaBSuperUser    areaBDeleteOnly

 areaCSuperUser    areaCCreateOnly
 areaCSuperUser    areaCReadOnly
 areaCSuperUser    areaCUpdateOnly
 areaCSuperUser    areaCDeleteOnly

auithitemassignment

|    itemname (pk)   |   userid (pk)   |
 areaABSuperUser      1

原来的答案会回来;

 |   name    |
 areaACreateOnly
 areaAReadOnly
 areaAUpdateOnly
 areaADeleteOnly

 areaBCreateOnly
 areaBReadOnly
 areaBUpdateOnly
 areaBDeleteOnly

 areaCSuperUser
 areaCCreateOnly
 areaCReadOnly
 areaCUpdateOnly
 areaCDeleteOnly

因为它过滤了父母和孩子,而不是孩子的孩子。 (我在第二个例子中)的结果是:

 |   name    |
 areaCSuperUser
 areaCCreateOnly
 areaCReadOnly
 areaCUpdateOnly
 areaCDeleteOnly

***编辑2:

特别针对Yii:

我已经对Yii进行了更多阅读,CAuthManager提供了许多有用的方法,包括hasItemChild()isAssigned()getItemChildren(),......等等,这可能有助于抓取我需要的数据

1 个答案:

答案 0 :(得分:1)

此查询可能会帮助您

SELECT DISTINCT `ai`.`name`
FROM `authitem` `ai`
LEFT JOIN `auithitemassignment` `aa`
ON `aa`.`itemname` = `ai`.`name` AND `aa`.`userid` = 1
WHERE  
`aa`.`itemname` IS NULL 
AND `ai`.`name` NOT IN (
    SELECT
    `aic`.`child` itemname
    FROM `authitemchild` `aic`
    JOIN `auithitemassignment` `aa`
    ON `aa`.`itemname` = `aic`.`parent`
    WHERE `aa`.`userid` = 1
)