首页 > 解决方案 > 分组选择第 n 行 Postgres

问题描述

我有一个属于“每组最大 n 组”类别的问题,但略有不同。我有一个表格,如下所示:

| t_id | t_amount | b_id | b_amount |
|------|----------|------|----------|
| 1    | 50       | 7    | 50       |
| 1    | 50       | 15   | 50       |
| 1    | 50       | 80   | 50       |
| 3    | 50       | 7    | 50       |
| 3    | 50       | 15   | 50       |
| 3    | 50       | 80   | 50       |
| 17   | 50       | 7    | 50       |
| 17   | 50       | 15   | 50       |
| 17   | 50       | 80   | 50       |

我想做的基本上是对这个表进行分区t_id,然后选择第一个分区的第一行、第二个分区的第二行和第三个分区的第三行,结果如下所示:

| t_id | t_amount | b_id | b_amount |
|------|----------|------|----------|
| 1    | 50       | 7    | 50       |
| 3    | 50       | 15   | 50       |
| 17   | 50       | 80   | 50       |

看起来像一个窗口函数或其他东西distinct on可能会起作用,但我还没有把它放在一起。

我在 *nix 系统上使用 Postgres 10。

标签: postgresqlgreatest-n-per-group

解决方案


使用窗口函数dense_rankrow_number会这样做

https://www.postgresql.org/docs/10/static/functions-window.html


解决方案:db<>fiddle

SELECT
    t_id,
    t_amount,
    b_id,
    b_amount
FROM
    (
        SELECT
            *,
            dense_rank() over (ORDER BY t_id) as group_number,          -- A
            row_number() over (PARTITION BY t_id ORDER BY t_id, b_id) 
                 as row_number_in_group                                 -- B
        FROM
            test_data) s
WHERE
    group_number = row_number_in_group

Adense_rank增加每个给定组的数量(超过 的分区t_id)。所以每个人都有t_id自己的价值。

Brow_number计算给定分区内的行数。

我在这里说明子查询的结果:

t_id  t_amount  b_id  b_amount  dense_rank  row_number  
----  --------  ----  --------  ----------  ----------  
1     50        7     50        1           1           
1     50        15    50        1           2           
1     50        80    50        1           3           
3     50        7     50        2           1           
3     50        15    50        2           2           
3     50        80    50        2           3           
17    50        7     50        3           1           
17    50        15    50        3           2           
17    50        80    50        3           3     

现在您必须过滤组内的组号等于行号的位置,然后您将获得预期的结果。


推荐阅读