如何解释Postgresql rank()关系

pu82cl6c  于 2022-11-29  发布在  PostgreSQL
关注(0)|答案(3)|浏览(135)

我有一个表teams,它有30行,有一些统计数据以属性的形式存储。例如,goals for,goals against等。我创建了一个视图,它使用rank()对记录进行了很好的排序。下面是一个简短的查询示例和结果表:

SELECT name,
   points, 
   rank() OVER (ORDER BY points DESC) AS point_tank
FROM teams;

         name          | points    | point_rank
-----------------------+-----------+----------------
 Team 1                |        14 |              1
 Team 2                |        11 |              2
 Team 3                |         9 |              3
 Team 4                |         9 |              3

我想添加一个额外的列,它将根据排名是否为平局返回布尔值。例如,本例中的Team 3和Team 4。它可能看起来像这样:

name          | points    | point_rank     | tie
-----------------------+-----------+----------------+----------------
 Team 1                |        14 |              1 |          false
 Team 2                |        11 |              2 |          false
 Team 3                |         9 |              3 |           true
 Team 4                |         9 |              3 |           true

这里有什么想法吗?或者我的方法不正确,在这里滥用了rank()?提前感谢!

w1jd8yoj

w1jd8yoj1#

您可以使用CTE,然后使用滞后/超前函数来检查是否有并列关系:

with ranked as (
  SELECT name,
        points, 
        rank() OVER (ORDER BY points DESC) AS point_rank
  FROM teams
)
select name, points, point_rank, 
       (   point_rank = lag(point_rank, 1, -1::bigint) over (order by point_rank) 
        or point_rank = lead(point_rank, 1, -1::bigint) over (order by point_rank)
       ) as is_tie
from ranked;

第一行和最后一行需要lag和lead函数的默认值,以避免在那里检查空值。
示例:https://dbfiddle.uk/-01aFLr4

pw136qt2

pw136qt22#

一种方法是将当前查询放入公用表表达式中,然后使用它来标识哪些排名重复:

WITH cte AS (
    SELECT name,
           points, 
           rank() OVER (ORDER BY points DESC) AS point_rank
    FROM teams;
)

SELECT cte.name,
       cte.points,
       cte.point_rank
       CASE WHEN t.point_rank IS NOT NULL THEN 'false' ELSE 'true' END AS tie
FROM cte
LEFT JOIN
(
    SELECT point_rank
    FROM cte
    GROUP BY point_rank
    HAVING COUNT(*) = 1
) t
    ON cte.point_rank = t.point_rank
xesrikrc

xesrikrc3#

SELECT name
   , points
   , rank() OVER (rrr) AS point_rank
   -- , count(*) OVER (ppp) AS ppp_cnt
   , rank() OVER (pp2) AS sub_rank
   , (COUNT(*) OVER (ppp) > 1) AS is_tie
FROM teams
WINDOW ppp AS (PARTITION BY points )
        , pp2 AS (PARTITION BY points ORDER BY ctid )
        , rrr AS (ORDER BY points DESC)
ORDER BY points DESC
        ;

结果(我额外添加了两行):

DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 6
  name  | points | point_rank | sub_rank | is_tie 
--------+--------+------------+----------+--------
 Team_1 |     14 |          1 |        1 | f
 Team_2 |     11 |          2 |        1 | f
 Team_3 |      9 |          3 |        1 | t
 Team_4 |      9 |          3 |        2 | t
 Team_5 |      5 |          5 |        1 | t
 Team_6 |      5 |          5 |        2 | t
(6 rows)

相关问题