2017-04-25 59 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