从玩家 ID 获取第一个和最后一个分数

Getting the first and last score from the Player ID

我正在尝试从中获取第一条和最后一条记录 table:

CREATE TABLE record(
  id SERIAL PRIMARY KEY,
  player_id BIGINT,
  score INT
);

INSERT INTO record(player_id,score) VALUES(603,15);
INSERT INTO record(player_id,score) VALUES(603,5);
INSERT INTO record(player_id,score) VALUES(604,15);
INSERT INTO record(player_id,score) VALUES(604,10);
INSERT INTO record(player_id,score) VALUES(604,15);
INSERT INTO record(player_id,score) VALUES(612,20);
INSERT INTO record(player_id,score) VALUES(612,5);
INSERT INTO record(player_id,score) VALUES(612,10);
INSERT INTO record(player_id,score) VALUES(612,15);

如何获得 player_id 单行的第一个和最后一个分数?因此,table 将如下所示:

|==========|============|===============|
|player_id | first_score| last_score    |
|==========|============|===============|
|603       | 15         | 5             |
|604       | 15         | 15            |
|612       | 20         | 15            |
|==========|============|===============|

这是我目前在 DB-Fiddle 中的内容,但我似乎无法正确理解:

https://www.db-fiddle.com/f/gLuJ1dbwg5Eor3SUrubpbe/1

我想我明白了...但是让我知道是否有更有效的方法来做到这一点:

SELECT
  first_scores.player_id,
  first_score,
  last_score
FROM
(
  SELECT
    record.player_id,
    record.id,
    score AS first_score
  FROM record
  INNER JOIN (
    SELECT
      player_id,
      MIN(record.id) AS min_record_id
    FROM record
    GROUP BY player_id
    ORDER BY player_id  
  ) AS min_scores
  ON min_record_id = record.id
) AS first_scores
INNER JOIN
(
  SELECT
    record.player_id,
    record.id,
    score AS last_score
  FROM record
  INNER JOIN (
    SELECT
      player_id,
      MAX(record.id) AS max_record_id
    FROM record
    GROUP BY player_id
    ORDER BY player_id  
  ) AS max_scores
  ON max_record_id = record.id  
) AS last_scores ON first_scores.player_id = last_scores.player_id

这是数据库 fiddle: https://www.db-fiddle.com/f/gLuJ1dbwg5Eor3SUrubpbe/4

这是 Postgres 中的 question which is typically done using distinct on ()

您需要一个查询来获取第一个分数,一个查询来获取最后一个分数(假设“第一个”和“最后一个”是通过 id 列定义的)

select fs.player_id, 
       fs.score as first_score, 
       ls.score as last_score
from (
  -- "first" score per player
  select distinct on (player_id) *
  from record
  order by player_id, id 
) fs
  left join (
    -- "last" score per player
    select distinct on (player_id) *
    from record
    order by player_id, id desc
  ) ls on ls.player_id = fs.player_id
order by player_id;

另一种选择(但可能效率较低)是使用 window function 对每个玩家的得分进行编号。然后使用过滤聚合将结果“透视”到两列中。

with numbered as (
  select player_id, 
         row_number() over (partition by player_id order by id) as rn_first,
         row_number() over (partition by player_id order by id desc) as rn_last,
         score
  from record
)
select player_id, 
       max(score) filter (where rn_first = 1) as first_score,
       max(score) filter (where rn_last = 1) as last_score
from numbered
where rn_first = 1 or rn_last = 1
group by player_id
order by player_id;       

Online example