MySQL中最有效的方法是在相同值之后进行过滤时从关系表中获取所有关联值

时间:2014-09-16 17:13:35

标签: mysql sql

简化我在MySQL中有两个表:一个持有一个人实体和一个关系表,它将多个权利与个人实体相关联。表格如下:

person_id | person_name
1         | Michael
2         | Kevin

person2right

person_id | right_id
1         | 1
1         | 2
1         | 4
2         | 1
2         | 2

我现在想要实现的是让所有人都包括所有相关权利,这些权利至少具有已定义的权利 - 在此示例中为right_id 1和4。

到目前为止我所使用的是subselect的查询,但我想知道是否有更有效的方法来实现我的目标而没有subselect,因为MySQL在加入subselect时无法使用索引。这是我的疑问:

SELECT person_name, GROUP_CONCAT(`person2right`.`right_id`) as `all_rights` 
FROM `person` 
LEFT JOIN `person2right` ON `person`.`person_id` = `person2right`.`person_id` 
LEFT JOIN (
    SELECT `person_id` FROM `person2right` WHERE `right_id` IN (1, 4) 
    GROUP BY `person_id` HAVING COUNT(`person2right`.`right_id`) >= 2
) as `p2r` ON `person`.`person_id` = `p2r`.`person_id` 
WHERE `p2r`.`person_id` IS NOT NULL GROUP BY `person_id`

也许某人有想法在没有子查询的情况下这样做。请帮助你。

提前谢谢!

3 个答案:

答案 0 :(得分:2)

这将仅选择具有权限1和权限4的人员(及其所有相关权利)。请注意,它与您的查询的不同之处在于您的查询选择所有人员(无论他们的权利如何)并且仅选择如果他们有权利1和4,他们的相关权利。

SELECT person_name, GROUP_CONCAT(`person2right`.`right_id`) as `all_rights` 
FROM `person` 
JOIN `person2right` ON `person`.`person_id` = `person2right`.`person_id` 
GROUP BY `person`.`person_id`
HAVING SUM(`right_id` = 4) > 0 AND SUM(`right_id` = 1) > 0

修改:如果person2right中的行是唯一的,那么您可以将having子句更改为

HAVING SUM(`right_id` IN (1,4)) = 2

答案 1 :(得分:1)

让我们看看其他联接是否可以解决问题:

select person_name, group_concat(distinct p2r.right_id) as all_rights
from person as p
     inner join person2right as p2r using (person_id) -- You don't need LEFT JOIN, because you'll only return persons with rights
     -- The new stuff starts here: Two new LEFT JOINs to track the rights you want
     left join person2right as p2r_1 using (person_id)
     left join person2right as p2r_4 using (person_id)
where
    -- Here is where you check if the rights exist
    (p2r_1.right_id = 1 and p2r_4.right_id = 4)
group by p.person_id;

看看this SQL fiddle example

答案 2 :(得分:0)

您可以尝试检查where子句中的权限(避免第二次左连接)

...
WHERE 2 = (select count(*) 
           from person2right 
           where person_id = person.person_id
                 and right_id in (1, 4))