如何在两个自连接列中选择不同的记录?

时间:2015-09-24 16:06:57

标签: sql postgresql

我有一个玩家表,我试图构建一个SQL查询来配置它们以分配特定回合的匹配。每个玩家都有一个分数,我想配对有相似分数的玩家。我不希望任何玩家出现在一对以上。

首先,我创建了以下视图:

CREATE VIEW all_possible_pairs AS
SELECT p1.id AS player1, p2.id AS player2 
FROM players as p1, players as p2
WHERE p1.id < p2.id
ORDER BY ABS(p1.score - p2.score)

all_possible_pairs获得所有可能的玩家对并避免玩家与他们自己匹配并且包括相同的一对两次(例如a,b b,a)。我按照我想要的方式对数据进行排序,使得首先出现的对优先于稍后出现的对(因为它们具有更接近的分数)。

我想从玩家第一次出现的all_possible_pairs中选择行。在结果表格中,每个玩家只应在两列中出现一次(例如,如果玩家首次出现在player2中,则不应出现在任何后续行中的player1或player2中)。

所以,例如,假设我们有玩家a,b,c,d和all_possible_players看起来像这样:

player1, player2
a        b
a        c
a        d
b        c
b        d
c        d

我想从此视图中进行选择,以便获得以下内容:

player1, player2
a        b
c        d

我现在正在尝试各种SELECT DISTINCT条款,但是我已经把头撞到了墙上一段时间,但我似乎无法做到这一点。例如,上例中的player1上的SELECT DISTINCT将包含b,c,这不是我想要的,因为它意味着b和c在表中两次。

2 个答案:

答案 0 :(得分:4)

不是列出所有可能的配对,而是创建一个视图,为每个玩家提供排名,而不是分数:

CREATE VIEW ranked_players AS
SELECT id AS Playerid, row_number() OVER (order by score) as PlayerRank
FROM players

现在当你配对它们时,将奇数排名的那些与它们相邻的偶数排名的邻居配对:

SELECT ranked1.PlayerId player1, 
    ranked2.PlayerId  player2
FROM ranked_players AS 
    ranked1
INNER JOIN ranked_players 
    AS ranked2 ON ranked1.
    PlayerRank+ 1 = ranked2.
    PlayerRank
WHERE ranked1.playerrank % 2 
    = 1

看看是否能满足您的需求。

答案 1 :(得分:4)

可能不完全是你想要的,但是:

with cte as 
(select *, row_number() over (order by score desc) as rn
 from players)
select *
from cte as t1 join cte as t2
  on t2.rn = t1.rn+1
where mod(t1.rn, 2) = 1
  and mod(t2.rn, 2) = 0

根据得分分配row_number n ,然后将 n n + 1

配对

fiddle