用于计算rotisserie棒球积分的PostgreSQL查询
我正试图编写一个PostgreSQL查询来计算虚拟棒球点数,如前所述。到目前为止,我所掌握的信息都可以在中找到,它正确地计算了每个统计数据的点数,但领带除外。平局团队的分数应按如下方式计算: 在打成平局的情况下,每一个参赛队都会得到一个平均的应付总分——即,在上面的例子中,如果两个队在一个类别中并列第一,每个队都会得到9.5分[(10+9)/2=9.5] 您可以在我的SQLfiddle中的和结果集中看到我的方法中的错误。在第一组结果中,与9支本垒打平手的球队各得3.5分(排名4和3的总和=7,除以2),而在第二组,与33 RBI平手的球队也各得3.5分(排名5、4、3和2的总和=14,除以4)用于计算rotisserie棒球积分的PostgreSQL查询,sql,postgresql,ranking,window-functions,Sql,Postgresql,Ranking,Window Functions,我正试图编写一个PostgreSQL查询来计算虚拟棒球点数,如前所述。到目前为止,我所掌握的信息都可以在中找到,它正确地计算了每个统计数据的点数,但领带除外。平局团队的分数应按如下方式计算: 在打成平局的情况下,每一个参赛队都会得到一个平均的应付总分——即,在上面的例子中,如果两个队在一个类别中并列第一,每个队都会得到9.5分[(10+9)/2=9.5] 您可以在我的SQLfiddle中的和结果集中看到我的方法中的错误。在第一组结果中,与9支本垒打平手的球队各得3.5分(排名4和3的总和=7,除
最简单的方法是什么来纠正这些错误,并将总分平均分配给排名靠前的团队?蛮力法可能是计算未经调整的排名,如下所示:
select hr, sum(raw) / count(*)
from (
select hr,
(select count(*) + 1 from stats) - row_number() over (order by hr desc) as raw
from stats
) r
group by hr
order by hr desc
并将其与stats表连接起来,以获得给定分数的分数。在我看来,如果示例不完整,最好在提供的字段中有一个候选键
SELECT
hr,rbi,
rank() OVER h AS hr_rank,
row_number() OVER h AS hr_rn,
count(*) OVER () - rank() OVER h + 1 AS hr_aprx,
rank() OVER r AS rbi_rank,
row_number() OVER r AS rbi_rn,
count(*) OVER () - rank() OVER r + 1 AS rbi_aprx,
count(*) OVER () AS cnt
FROM
stats
WINDOW h AS (ORDER BY hr DESC), r AS (ORDER BY rbi DESC);
此查询提供的信息与前两个查询相同。如果您查看该表的EXPLAIN(analyze,buffers)
输出,您将看到该表只被访问一次
我在这里将点列命名为%\u aprx
,因为这些是近似点,我们必须计算平均值
%\u aprx
列进行数据分组。我将在这里使用,因为我发现命名子查询看起来更好avg()
调用的结果类型转换为float
,以除去一系列的零。不过,你可以选择在这里代替
我还添加了两个订购条件,因为仅凭ttl_pts
订购是不够的
请注意,在外部查询的窗口定义中,
orderby
故意漏掉。有了它,您将获得运行平均效果(您可以更改查询并查看您自己)。这是一个好的开始,但对于十个统计数据中的每一个,重复该子查询(使用联接)将变得相当笨拙。希望有一种更简单的方法。笨拙在SQL中并不少见。也许它可以以某种方式转换成一个函数,其中stats列是一个参数。Postgres足够聪明,可以避免对内部子查询进行重复扫描。您可以通过查看EXPLAIN
输出来确认这一点。您可以解释模式中的hr
和rbi
是什么吗?此外,如果你瞄准和浮动分数(如9.5
),为什么要使用integer
而不是numeric
类型?HR和RBI是我想要排名的值——在这种情况下,对于棒球队也是如此。这些都是整数,但是在平局的情况下,球队的排名应该是平均的,就像我问题中的雅虎链接一样。太棒了!是的,我的例子遗漏了一些细节,但我是故意这样做的。我将其简化为一个“最小工作示例”,因为我运行此查询的“表”实际上是另一个复杂嵌套查询的结果,该查询汇总了各个游戏的团队结果,我不想让问题看起来比实际情况更复杂。使用您的解决方案,我可以定期使用聚合结果构建一个临时表,或者调整它以运行聚合查询。谢谢
WITH ranks AS (
SELECT
hr, rbi,
rank() OVER h AS hr_rank,
row_number() OVER h AS hr_rn,
count(*) OVER () - rank() OVER h + 1 AS hr_aprx,
rank() OVER r AS rbi_rank,
row_number() OVER r AS rbi_rn,
count(*) OVER () - rank() OVER r + 1 AS rbi_aprx,
count(*) OVER () AS cnt
FROM
stats
WINDOW h AS (ORDER BY hr DESC), r AS (ORDER BY rbi DESC)
)
SELECT
hr, rbi,
(avg(hr_rn) OVER h)::float AS hr_pts,
(avg(rbi_rn) OVER r)::float AS rbi_pts,
(avg(hr_rn) OVER h + avg(rbi_rn) OVER r)::float AS ttl_pts
FROM
ranks
WINDOW h AS (PARTITION BY hr_aprx), r AS (PARTITION BY rbi_aprx)
ORDER BY
ttl_pts DESC, hr_pts DESC;