3

我有一个 PostgreSQL 表,它主要是一个桥接表,但它也有一些额外的东西。

本质上,它包含有关游戏中玩家的信息。所以我们有一个游戏中玩家实例的唯一ID。然后一个 id 是 FK 到游戏表,一个 id 是 FK 到玩家表。还有一些其他无关紧要的东西。像这样的东西:

Table players_games
| id        | 12564
| player_id | 556
| game_id   | 156184

我想做的是找出一个玩家和另一个玩家一起玩的次数。所以,如果player1和player2在同一个游戏中,他们就一起玩过一次。一场比赛有 2 个以上的玩家。

所以我想做的是填充一个新表,它包含三个值:player_lo、player_hi、times_played。

并且每对有一行和他们玩的次数,或者如果最终效率更高,则每次迭代都有一行并将值设置为 1,以便以后可以将它们加在一起,也许是分布的。所以你可能会看到类似的东西:

p1, p2, 1
p1, p2, 1

这些后来减少为:

p1, p2, 2

所以我想知道在开始编写一个稍微复杂的 python 脚本来做之前,是否有一些聪明的方法可以用 SQL 来做这件事,或者是否有 SQL 可以减少我的编程工作量。

4

3 回答 3

3
select p1, p2, count(*) from (
    select 
      pg1.player_id as p1, pg1.game_id, pg2.player_id as p2
    from
      players_games pg1, players_games pg2
    where
      pg1.game_id = pg2.game_id and pg1.player_id != pg2.player_id
) foo
group by p1, p2

请注意,这会进行完全连接,players_games因此如果表很大,它可能会非常慢。关键部分是group by获取计数。

于 2012-05-20T13:00:02.537 回答
3

为此,您需要在 player_games 表上进行自联接。第一个子查询针对第一个玩家,第二个针对第二个玩家。“第一个”玩家是具有较低玩家 ID 的玩家。

select pg1.player_id as player1, pg2.player_id as player2, count(*) as num_games
from (select distinct game_id, player_id
      from  players_games pg
     ) pg1 join
     (select distinct game_id, player_id
      from players_games pg
     ) pg2
     on pg1.game_id = pg2.game_id and
        pg1.player_id < pg2.player_id
group by pg1.player_id, pg2.player_id

请注意,加入条件在玩家 ID 上使用“<”。这是为了防止重复计数(因此玩家 A、B 不会也算作 B、A)。

此外,我在内部子查询中添加了一个“distinct”,以防单个玩家可能在给定游戏中出现多次。也许这不是必需的。可以肯定的是,您应该在复合键 game_id、player_id 上有一个唯一索引。

于 2012-05-20T13:26:35.720 回答
0
SET search_path='tmp';
DROP TABLE players_game CASCADE;
CREATE TABLE players_game
        ( game_id INTEGER NOT NULL
        , player_id INTEGER NOT NULL
        );
INSERT INTO players_game(game_id,player_id) VALUES
 (1,100) ,(1,101) ,(2,100) ,(2,101)
,(3,100) ,(3,101) ,(4,102) ,(4,101)
        ;

WITH pair AS (
    SELECT g1.player_id AS p1
     , g2.player_id AS p2
    FROM players_game g1
    JOIN players_game g2 ON g1.game_id = g2.game_id
    WHERE g1.player_id < g2.player_id
    )
SELECT pa.p1 , pa.p2, COUNT(*) AS num_games
FROM pair pa
GROUP BY p1, p2
ORDER BY num_games DESC
        ;

结果:

SET
ERROR:  table "players_game" does not exist
CREATE TABLE
INSERT 0 8
 p1  | p2  | num_games 
-----+-----+-----------
 100 | 101 |         3
 101 | 100 |         3
 102 | 101 |         1
 101 | 102 |         1
(4 rows)
于 2012-05-20T14:27:07.487 回答