很长一段时间以来,我一直在努力解决问题,但是我没有取得任何进展。基本上,我有两个表players
和matches
。 players
中的每个玩家都有一个唯一的player_id
,以及一个group_id
来标识他/她属于哪个组。 matches
中的每场比赛都有两名球员player_id
和first_player
中的second_player
人,他们总是来自同一组。 first_score
对应于first_player
得分的分数,second_score
对应于second_player
得分的分数。得分更高的人赢得比赛。这是两个表:
create table players (
player_id integer not null unique,
group_id integer not null
);
create table matches (
match_id integer not null unique,
first_player integer not null,
second_player integer not null,
first_score integer not null,
second_score integer not null
);
现在我想做的是让每个小组中获胜最多的球员,他们的小组ID和获胜次数。因此,例如,如果有三个组,结果将类似于:
Group Player Wins
1 24 23
2 13 25
3 34 20
这就是我现在拥有的
SELECT p1.group_id AS Group, p1.player_id AS Player, COUNT(*) AS Wins
FROM players p1, matches m1
WHERE (m1.first_player = p1.player_id AND m1.first_score > m1.second_score)
OR (m1.second_player = p1.player_id AND m1.second_score > m1.first_score)
GROUP BY p1.group_id
HAVING COUNT(*) >= (
SELECT COUNT(*)
FROM players p2, matches m2
WHERE p2.group_id = p1.group_id AND
((m2.first_player = p2.player_id AND m2.first_score > m2.second_score)
OR (m2.second_player = p2.player_id AND m2.second_score > m2.first_score))
)
我的想法是仅选择获胜大于或等于该组中所有其他玩家的获胜者。我的查询存在一些语法问题。我想我也错误地使用了GROUP BY。
在获胜次数上也存在平局的问题,我应该只让player_id
最少的玩家获胜。但是我还没到那个地步。非常感谢您的帮助,谢谢!
编辑1
我有一些样本数据用于运行查询。
SELECT * FROM players
给了我这个:
Player_ID Group_ID
100 1
200 1
300 1
400 2
500 2
600 3
700 3
SELECT * FROM matches
给了我这个:
match_id first_player second_player first_score second_score
1 100 200 10 20
2 200 300 30 20
3 400 500 30 10
4 500 400 20 20
5 600 700 20 10
因此,查询应返回:
Group Player Wins
1 200 2
2 400 1
3 600 1
按原样运行查询将返回以下错误:
ERROR: column "p1.player_id" must appear in the GROUP BY clause or be used in an aggregate function
现在我了解,如果我想在SELECT(或HAVING)语句中使用player_id
,则必须在GROUP BY子句中指定它,但我不希望按玩家ID分组,只能按组ID。
即使我确实在外部查询中将p1.player_id添加到GROUP BY,也实际上得到了正确的答案。但是我有点困惑。分组依据是否不根据该列汇总表?从逻辑上讲,我只想按p1.group_id分组。
此外,如果我要在一组中拥有最多获胜次数最多的玩家,我该如何保持player_id
最少的玩家?
编辑2
如果我将matches
表更改为第1组,则有两名玩家各赢1个,则查询结果将从结果中完全忽略第1组。
因此,如果我的matches
表是:
match_id first_player second_player first_score second_score
1 100 200 10 20
2 200 300 10* 20
3 400 500 30 10
4 500 400 20 20
5 600 700 20 10
我希望结果是
Group Player Wins
1 200 1
1 300 1
2 400 1
3 600 1
但是,我得到以下信息:
Group Player Wins
2 400 1
3 600 1
请注意,所需结果是
Group Player Wins
1 200 1
2 400 1
3 600 1
因为我希望在平局时只选择player_id
最少的玩家。
答案 0 :(得分:0)
尝试如下
with cte as
(
select p.Group_ID,t1.winplayer,t1.numberofwin
row_number()over(partition by p.Group_ID order by t1.numberofwin desc,t1.winplayer) rn from players p join
(
SELECT count(*) as numberofwin,
case when first_score >second_score then first_player
else second_player end as winplayer
FROM matches group by case when first_score >second_score then first_player
else second_player end
) t1 on p.Player_ID =t1.winplayer
) select * from cte where rn=1
答案 1 :(得分:0)
当您在GROUP BY中添加player_id
时,此方法有效,因为您知道每个玩家仅在一个组中玩。因此,您可以按玩家分组。因此,从逻辑上讲,您可以将player_id
添加到GROUP BY。
答案 2 :(得分:0)
WITH first_players AS (
SELECT group_id,player_id,SUM(first_score) AS scores FROM players p LEFT JOIN matches m ON p.player_id=m.first_player GROUP BY group_id,player_id
),
second_players AS (
SELECT group_id,player_id,SUM(second_score) AS scores FROM players p LEFT JOIN matches m ON p.player_id=m.second_player GROUP BY group_id,player_id
),
all_players AS (
WITH al AS (
SELECT group_id, player_id, scores FROM first_players
UNION ALL
SELECT group_id, player_id, scores FROM second_players
)
SELECT group_id, player_id,COALESCE(SUM(scores),0) AS scores FROM al GROUP BY group_id, player_id
),
players_rank AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY group_id ORDER BY scores DESC, player_id ASC) AS score_rank,
ROW_NUMBER() OVER(PARTITION BY scores ORDER BY player_id ASC) AS id_rank FROM all_players ORDER BY group_id
)
SELECT group_id, player_id AS winner_id FROM players_rank WHERE score_rank=1 AND id_rank=1
结果
group_id winner_id
1 45
2 20
3 40