2015-10-19 55 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

我的修改版本适用于所有情况,包括您提到的情况。 –