使用附加(不同)过滤器聚合列

ave*_*ave 4 sql postgresql aggregate-functions aggregate-filter

这段代码按预期工作,但我很长而且令人毛骨悚然。

select p.name, p.played, w.won, l.lost from

(select users.name, count(games.name) as played
from users
inner join games on games.player_1_id = users.id
where games.winner_id > 0
group by users.name
union
select users.name, count(games.name) as played
from users
inner join games on games.player_2_id = users.id
where games.winner_id > 0
group by users.name) as p

inner join

(select users.name, count(games.name) as won
from users
inner join games on games.player_1_id = users.id
where games.winner_id = users.id
group by users.name
union
select users.name, count(games.name) as won
from users
inner join games on games.player_2_id = users.id
where games.winner_id = users.id
group by users.name) as w on p.name = w.name

inner join

(select users.name, count(games.name) as lost
from users
inner join games on games.player_1_id = users.id
where games.winner_id != users.id
group by users.name
union
select users.name, count(games.name) as lost
from users
inner join games on games.player_2_id = users.id
where games.winner_id != users.id
group by users.name) as l on l.name = p.name
Run Code Online (Sandbox Code Playgroud)

如您所见,它由 3 个用于检索的重复部分组成:

  • 玩家姓名和他们玩的游戏数量
  • 玩家姓名和他们赢得的游戏数量
  • 球员姓名和他们输掉的比赛数量

每一个也由两部分组成:

  • 玩家姓名和他们作为玩家_1参与的游戏数量
  • 玩家名称和他们作为玩家_2参与的游戏数量

这怎么能简化?

结果如下所示:

           name            | played | won | lost 
---------------------------+--------+-----+------
 player_a                  |      5 |   2 |    3
 player_b                  |      3 |   2 |    1
 player_c                  |      2 |   1 |    1
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 7

Postgres 9.4或更新版本中的聚合FILTER子句更短更快:

SELECT u.name
     , count(*) FILTER (WHERE g.winner_id  > 0)    AS played
     , count(*) FILTER (WHERE g.winner_id  = u.id) AS won
     , count(*) FILTER (WHERE g.winner_id <> u.id) AS lost
FROM   games g
JOIN   users u ON u.id IN (g.player_1_id, g.player_2_id)
GROUP  BY u.name;
Run Code Online (Sandbox Code Playgroud)

在 Postgres 9.3 中(或任何版本)中,这仍然比嵌套的子选择或CASE表达式更短和更快:

SELECT u.name
     , count(g.winner_id  > 0 OR NULL)    AS played
     , count(g.winner_id  = u.id OR NULL) AS won
     , count(g.winner_id <> u.id OR NULL) AS lost
FROM   games g
JOIN   users u ON u.id IN (g.player_1_id, g.player_2_id)
GROUP  BY u.name;
Run Code Online (Sandbox Code Playgroud)

细节: