sql - 如何从相邻表中动态数量的相关行获取聚合数据

标签 sql postgresql aggregate-functions postgresql-9.4

我有一个比赛表,大致如下:

player_id | match_id | result | opponent_rank
----------------------------------------------
82        | 2847     |   w    |   42
82        | 3733     |   w    |  185
82        | 4348     |   l    |   10
82        | 5237     |   w    |  732
82        | 5363     |   w    |   83
82        | 7274     |   w    |    6
51        | 2347     |   w    |   39
51        | 3746     |   w    |  394
51        | 5037     |   l    |   90
...       | ...      |  ...   |  ...

为了获得所有连胜(不仅仅是任何玩家的最高连胜),我使用以下查询:

SELECT player.tag, s.streak, match.date, s.player_id, s.match_id FROM (
    SELECT streaks.streak, streaks.player_id, streaks.match_id FROM (
        SELECT w1.player_id, max(w1.match_id) AS match_id, count(*) AS streak FROM (
            SELECT w2.player_id, w2.match_id, w2.win, w2.date, sum(w2.grp) OVER w AS grp FROM (
                SELECT m.player_id, m.match_id, m.win, m.date, (m.win = false AND LAG(m.win, 1, true) OVER w = true)::integer AS grp FROM matches_m AS m
                WHERE matches_m.opponent_position<'100'
                    WINDOW w AS (PARTITION BY m.player_id ORDER BY m.date, m.match_id)
                    ) AS w2
                    WINDOW w AS (PARTITION BY w2.player_id ORDER BY w2.date, w2.match_id)
                ) AS w1
            WHERE w1.win = true
            GROUP BY w1.player_id, w1.grp
            ORDER BY w1.player_id DESC, count(*) DESC
        ) AS streaks
    ORDER BY streaks.streak DESC
    LIMIT 100
    ) AS s
LEFT JOIN player ON player.id = s.player_id
LEFT JOIN match ON match.id = s.match_id

结果如下所示(请注意,这不是固定的表/ View ,因为上面的查询可以通过某些参数进行扩展,例如国籍、日期范围、玩家排名等):

player_id | match_id | streak
-------------------------------
82        | 3733     |  2
82        | 7274     |  3
51        | 3746     |  2
...       | ...      |  ...

我现在想要添加的是一堆汇总数据,以提供有关连胜的详细信息。首先,我想知道每次连胜期间对手的平均排名。其他数据包括连续的持续时间、第一个和最后一个日期、结束连续的对手姓名或连续的对手名称,等等。我尝试过各种方法 - CTE、一些精心设计的联接、联合,或者将它们作为滞后函数添加到现有代码中。但我完全不知道如何解决这个问题。

从代码中可以明显看出,我的 SQL 技能非常基础,所以请原谅任何错误或低效的语句。对于完整的上下文,我在 Debian 上使用 Postgres 9.4,matches_m 表是一个具有 550k 行的物化 View (查询现在需要 2.5 秒)。数据来自http://aligulac.com/about/db/ ,我只是镜像它来创建上述 View 。

最佳答案

我认为这符合你的要求。

关键思想是为每个连胜分配一个“连胜组”,这样您就可以将它们聚合起来。您可以通过观察来做到这一点:

  1. 一场连胜的比赛显然是一场“胜利”。
  2. 可以通过计算之前的失败次数来识别连胜 - 这对于连胜来说是恒定的。

Postgres 在 9.4 中引入了 filter 子句,这使得语法变得更简单:

select player_id, count(*) as streak_length,
       avg(opponent_rank) as avg_opponent_rank
from (select m.*,
             count(*) filter (where result = 'l') over (partition by player_id order by date) as streak_grp
      from matches_m m
     ) m
where result = 'w'
group by player_id, streak_grp;

关于sql - 如何从相邻表中动态数量的相关行获取聚合数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52024244/

相关文章:

SQL - 服务器上所有数据库的 INFORMATION_SCHEMA

sql - 在postgresql中将行转换为字符串

c# - 查询不会从 npgsql 运行,而是在 postgresql pgAdmin 上运行

arrays - 聚合多维数组的函数中的初始数组

php - 查询需要优化还是我只需要更高的最大连接数?

MySQL:如何将参数传递给触发器

PostgreSQl 在创建新实体时正确锁定

postgresql - 修改 COALESCE 函数以考虑结果的两个相邻值

SQL查询返回与逗号分隔字符串具有相同ID的元素

c# - LINQ 表达式中的聚合函数抛出错误。 (不能翻译成商店表达式。)