2015-10-19 56 views
1

如何選擇所有尚未與'alpha'配對的玩家? (輸出='gamma')。它應該工作,即使對錶是空的。MySQL查詢對

table: players 
+----------+-------+ 
| playerID | name | 
+----------+-------+ 
|  1 | alpha | 
|  2 | beta | 
|  3 | gamma | 
+----------+-------+ 

table: pairs 
+---------+---------+ 
| player1 | player2 | 
+---------+---------+ 
|  2 |  3 | 
|  1 |  2 | 
+---------+---------+ 

我一直在掙扎幾個小時。對於例如如果我這樣做

SELECT p.*, r.* 
FROM players p 
JOIN pairs r 
    ON (player1 = playerID) OR (player2 = playerID) 
WHERE 
    ((r.player1 != 1) AND (r.player2 != 1)); 

輸出是'beta'和'gamma'。在連接中,'beta'出現兩次(每次與'alpha'和'gamma'配對)。 WHERE條件消除了一行'beta'。我想要的是'貝塔'的所有行都被消除。我是新手,嘗試過GROUP BY,HAVING等等的各種組合,我無法讓它工作。

SQL Fiddle here.

+0

你還在努力解決這個問題嗎? – AdamMc331

+0

不,我不知道如何更喜歡我的解決方案(在我的編輯)比答案,因爲我不使用「不在」。但我真的很感謝下面的答案。謝謝 –

+4

很高興它的工作!您可以隨時回答自己的問題並接受它,這可能會對未來的讀者更有幫助,他們會將您的編輯誤認爲是問題的一部分,而不是解決方案。 – AdamMc331

回答

3

我會打破這種分解成更小的比特和拼湊一起。首先獲得阿爾法球員的編號:

SELECT playerID 
FROM players 
WHERE name = 'alpha'; 

下一步是弄清楚如何排除。我會得到誰被選擇所有player2值,其中PLAYER1是「阿爾法」和所有PLAYER1值,其中player2是「阿爾法」這樣的搭配玩家1.我做這一切的球員名單:

SELECT p.player2 
FROM pairs p 
JOIN(
    SELECT playerID 
    FROM players 
    WHERE name = 'alpha') b ON b.playerID = p.player1 
UNION 
SELECT p.player1 
FROM pairs p 
JOIN(
    SELECT playerID 
    FROM players 
    WHERE name = 'alpha') b ON b.playerID = p.player2; 

一旦你這樣做了,剩下的唯一步驟是從球員那裏的人是1)沒有α和2)未在上面的列表中拉:這裏

SELECT * 
FROM players 
WHERE playerID NOT IN(
    SELECT playerID 
    FROM players 
    WHERE name = 'alpha') 
AND playerID NOT IN(
    SELECT p.player2 
    FROM pairs p 
    JOIN(
    SELECT playerID 
    FROM players 
    WHERE name = 'alpha') b ON b.playerID = p.player1 
    UNION 
    SELECT p.player1 
    FROM pairs p 
    JOIN(
    SELECT playerID 
    FROM players 
    WHERE name = 'alpha') b ON b.playerID = p.player2); 

SQL Fiddle例子。

+0

感謝您的方法的詳細解釋和分解。 –

1

像這樣的東西應該適用於這種情況。

SELECT 
    pl.* 
FROM 
    players as pl 
WHERE 
    pl.playerID NOT IN 
    (
     SELECT 
      p.player2 
     FROM 
      pairs AS p 
     INNER JOIN 
      players plr ON plr.playerID = p.player1 
     WHERE 
      plr.name='alpha' 

    ) 

如果玩家1和玩家2成對錶中的列更改位置,則可能必須在子查詢中使用CASE。

1

這應做到:

drop table pair; 
drop table player; 

create table player (
    id int, 
    name varchar(32) 
); 

create table pair (
    id1 int, 
    id2 int 
); 

insert into player values (1, 'Andy'); 
insert into player values (2, 'Bob'); 
insert into player values (3, 'Carl'); 
insert into player values (4, 'Dave'); 

insert into pair values (2, 3); 
insert into pair values (1, 2); 
insert into pair values (3, 1); 

select * from player where id not in (
select 
    if(pair.id1 = player.id, pair.id2, pair.id1) as other_player 
from 
    pair 
    join player on pair.id1 = player.id or pair.id2 = player.id 
where 
    player.name = 'Andy' 
) 
; 
+0

確保結果不會返回Andy – Drew

+1

@Drew:作爲學生的練習;) – John

+0

...例如,您可以做一個連接而不是子選項,並將其添加到您的where子句中,如「and player」。 id!= joined_table.id「 – John

0

備用解決方案,不使用「NOT IN」。

方法:(所有用戶) - (所有現有的對手)

這樣,即使(所有現有的對手)IS NULL。

SELECT p.* FROM players p 
LEFT JOIN (
    SELECT CASE 
      WHEN (player1 = 1) THEN player2 
      WHEN (player2 = 1) THEN player1 
     END AS opponentID 
    FROM pairs) existingOpponents 
ON (p.playerID = existingOpponents.opponentID) 
WHERE (existingOpponents.opponentID IS NULL) AND 
    (p.playerID != 1); 
+0

對於從未玩過任何人的新玩家(我認爲這個玩家不會出現在結果集中,但應該),會發生什麼?我確實喜歡這種方法。 – John

+0

我的修改版本適用於所有情況,包括您提到的情況。 –