SQL 聚合唯一对
Posted
技术标签:
【中文标题】SQL 聚合唯一对【英文标题】:SQL aggregate unique pairs 【发布时间】:2012-05-20 12:56:02 【问题描述】:我有一个 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
所以我想知道是否有一些巧妙的方法可以使用 SQL 来完成此任务,或者是否有 SQL 可以减少我的编程工作量,然后才开始编写一个稍微复杂的 python 脚本来执行此操作。
【问题讨论】:
【参考方案1】:为此,您需要在 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 上使用“
另外,我在内部子查询中添加了一个“distinct”,以防单个玩家可能在给定游戏中出现多次。也许这不是必需的。可以肯定的是,您应该在复合键 game_id、player_id 上有一个唯一索引。
【讨论】:
那里的语法似乎有些问题:错误:缺少表“p1”的 FROM 子句条目【参考方案2】: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
。
【讨论】:
在这种情况下你会考虑 100,000,000 行“大”吗? 我会将!=
更改为<
(或>
),否则您将重复计算所有对。
@wildplasser;你的意思是你会同时拥有 p1, p2
和 p2, p1
?这不是重点吗?
是的。我不知道 OP 的确切意图(我不太清楚......)可能是任何一种方式......
@wildplasser:我很确定,您对>
而不是!=
的评论是准确的。实际上,它将列出(p1, p2)
两次(以相反的顺序,具有相同的计数)。除此之外,这是关系除法的一个特例。我们收集了很多关于 in this related question 的信息。【参考方案3】:
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)
【讨论】:
以上是关于SQL 聚合唯一对的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch 分组聚合查询(bucket) --- 2022-04-03