2017-04-25 71 views
3

比方说,我有个人的ID(1-8)和人的角色(1-4)作为这样的一个表:选择重复的/不重复计数或组计数N值BY

CREATE TABLE personRole (
PersonId int NOT NULL, 
RoleId int NOT NULL 
); 

INSERT INTO personRole 
VALUES 
(1, 1), 
(1, 2), 
(2, 1), 
(2, 3), 
(3, 3), 
(4, 3), 
(1, 4), 
(5, 2), 
(6, 1), 
(7, 1), 
(7, 4), 
(8, 1), 
(8, 2), 
(8, 4) 
; 

我的目标是选择人物ID的谁拥有3点或更多的角色和角色是专门1,2,4,这是我的第一个解决方案:

SELECT PersonId FROM personRole 
WHERE RoleID in (1,2,4) 
GROUP BY PersonId 
HAVING count(*) >= 3 

但后来有人告诉我,这样做没有GROUP BY,因为它是慢,所以我想出了这个解决方案:

SELECT distinct PersonId 
FROM 
(
    SELECT PersonId, count(*) over(partition by PersonId) AS pcount 
    FROM (SELECT * FROM personRole WHERE RoleID in (1,2,4)) AS A 
) AS S 
WHERE pcount >= 3 

我已经包含这些举例来说明我正在努力实现的目标。 但现在我已被告知尝试不计数。我目前能够找到具有重复/重复的人的ID这样的所有行:

SELECT personId 
FROM personRole AS a 
WHERE EXISTS (
    SELECT 1 
    FROM personRole AS a2 
    WHERE a2.PersonId = a.PersonId 
    AND a2.RoleID <> a.RoleID 
); 

但我坚持试图找出如何只能选择他们,如果他们重复3次以上。如果我能够,那么我怀疑我可以只用INTERSECT它:

SELECT PersonId FROM personRole 
WHERE RoleID in (1,2,4) 

为了得到我的完整解决方案。我到目前为止正确解决这个问题,还是我的方向不对?

+0

它不能大于3可以吗?我认为你应该重新审视你的原始查询,并探究为什么它很慢。 – Strawberry

回答

3

通过“无数”,独裁者意味着没有聚合函数?你总是可以总结(1)而不是计数(*)。

否则,请尝试自我加入。

select a.PersonId, 
    a.RoleId, 
    b.RoleId, 
    c.RoleId, 
    d.RoleId 
from personRole a 
    left join personRole b 
    on a.PersonId = b.PersonId 
    and a.RoleId <> b.RoleId 
left join personRole c 
    on a.PersonId = c.PersonId 
    and a.RoleId <> c.RoleId 
    and b.RoleId <> c.RoleId 
left join personRole d 
    on a.PersonId = d.PersonId 
    and a.RoleId <> d.RoleId 
    and b.RoleId <> d.RoleId 
    and c.RoleId <> d.RoleId 
order by a.PersonId, a.RoleId 
; 

+----------+--------+--------+--------+--------+ 
| PersonId | RoleId | RoleId | RoleId | RoleId | 
+----------+--------+--------+--------+--------+ 
|  1 |  1 |  4 |  2 | NULL | 
|  1 |  1 |  2 |  4 | NULL | 
|  1 |  2 |  4 |  1 | NULL | 
|  1 |  2 |  1 |  4 | NULL | 
|  1 |  4 |  2 |  1 | NULL | 
|  1 |  4 |  1 |  2 | NULL | 
|  2 |  1 |  3 | NULL | NULL | 
|  2 |  3 |  1 | NULL | NULL | 
|  3 |  3 | NULL | NULL | NULL | 
|  4 |  3 | NULL | NULL | NULL | 
|  5 |  2 | NULL | NULL | NULL | 
|  6 |  1 | NULL | NULL | NULL | 
|  7 |  1 |  4 | NULL | NULL | 
|  7 |  4 |  1 | NULL | NULL | 
|  8 |  1 |  2 |  4 | NULL | 
|  8 |  1 |  4 |  2 | NULL | 
|  8 |  2 |  1 |  4 | NULL | 
|  8 |  2 |  4 |  1 | NULL | 
|  8 |  4 |  2 |  1 | NULL | 
|  8 |  4 |  1 |  2 | NULL | 
+----------+--------+--------+--------+--------+ 
20 rows in set (0.00 sec) 

限制与查找值c.RoleId where子句 - 并使用你的幻数宰杀笛卡尔乘积像这样:如果你想让它更加紧凑

select a.PersonId, 
     a.RoleId, 
     b.RoleId, 
     c.RoleId 
from personRole a 
left join personRole b 
    on a.PersonId = b.PersonId 
left join personRole c 
    on a.PersonId = c.PersonId 
where 
    b.RoleId <> a.RoleId 
    and b.RoleId <> c.RoleId 
    and c.RoleId <> a.RoleId 
    and c.RoleId <> b.RoleId 
    and a.RoleId = 1 
    and b.RoleId = 2 
    and c.RoleId = 4 
order by a.PersonId, a.RoleId 
; 

+----------+--------+--------+--------+ 
| PersonId | RoleId | RoleId | RoleId | 
+----------+--------+--------+--------+ 
|  1 |  1 |  2 |  4 | 
|  8 |  1 |  2 |  4 | 
+----------+--------+--------+--------+ 
2 rows in set (0.00 sec) 

,而你只是寻找这一个情况下,你可以不设左联接和值的比较一起

mysql> select a.PersonId, 
    ->  a.RoleId, 
    ->  b.RoleId, 
    ->  c.RoleId 
    -> from personRole a, 
    ->  personRole b, 
    ->  personRole c 
    -> where 
    ->  a.PersonId = b.PersonId 
    ->  and a.PersonId = c.PersonId 
    ->  and a.RoleId = 1 
    ->  and b.RoleId = 2 
    ->  and c.RoleId = 4 
    -> order by a.PersonId, a.RoleId 
    -> ; 
+----------+--------+--------+--------+ 
| PersonId | RoleId | RoleId | RoleId | 
+----------+--------+--------+--------+ 
|  1 |  1 |  2 |  4 | 
|  8 |  1 |  2 |  4 | 
+----------+--------+--------+--------+ 
2 rows in set (0.00 sec) 
+1

这是一个很棒的解决方案!谢谢!感谢您提供关于总结的提示,我会把它放在我的口袋里。不知道我是否受限于所有总量,但你给了两者的提示。 – Ryan

+0

你能解释一下吗?...对你有好处 –

+1

这个问题如何解决'只重复3次或更多次就选择它们'和'角色特别是1,2和4'这部分问题? –

2

你可以做自连接,虽然我不知道,这将是多的电子不如您的其他解决方案。它会摆脱任何聚合函数,因为你似乎被限制使用它们。

select a.PersonId 
from personRole a 
    join personRole b on a.PersonId = b.PersonId 
     and b.RoleId = 2 
    join personRole c on a.PersonId = c.PersonId 
     and c.RoleId = 4 
where a.RoleId = 1