Reputation: 5503
How can I select all players that have not been already paired with 'alpha' ? (output = 'gamma'). It should work even when the pairs table is empty.
table: players
+----------+-------+
| playerID | name |
+----------+-------+
| 1 | alpha |
| 2 | beta |
| 3 | gamma |
+----------+-------+
table: pairs
+---------+---------+
| player1 | player2 |
+---------+---------+
| 2 | 3 |
| 1 | 2 |
+---------+---------+
I have been struggling for several hours now. For e.g. if I do this
SELECT p.*, r.*
FROM players p
JOIN pairs r
ON (player1 = playerID) OR (player2 = playerID)
WHERE
((r.player1 != 1) AND (r.player2 != 1));
the output is 'beta' and 'gamma'. In the join, 'beta' appears twice (once each for its pairing with 'alpha' and 'gamma'). And the WHERE condition eliminates one row of 'beta'. What I want is for all rows of 'beta' to be eliminated. I am new to this and tried various combinations of GROUP BY, HAVING etc. I'm not able to get it to work.
Upvotes: 1
Views: 1495
Reputation: 5503
An alternate solution, without using "NOT IN".
Approach: (all users) - (all existing opponents)
This works even when (all existing opponents) 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);
Upvotes: 0
Reputation: 16690
I would break this down into smaller bits and piece it together. Start by getting the id of the player who is alpha:
SELECT playerID
FROM players
WHERE name = 'alpha';
The next step would be to figure out how to exclude. I'd get a list of all players who were paired with player 1. I did this by selecting all player2 values where player1 is 'alpha' and all player1 values where player2 is 'alpha' like this:
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;
Once you've done that, the only step that remains is to pull from player where the person is 1) not alpha and 2) not in the above list:
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 example here.
Upvotes: 3
Reputation: 3996
This should do it:
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'
)
;
Upvotes: 1
Reputation: 1766
Something like this should work for this scenario.
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'
)
In case player1 and player 2 columns in pairs table changes position, you may have to use a CASE inside the subquery.
Upvotes: 1