分块查询中的全局行号

Global row numbers in chunked query

我想在我的结果集中包含一列 row_number,其中包含行号序列,其中 1 是最新的项目,没有间隙。这有效:

SELECT id, row_number() over (ORDER BY id desc) AS row_number, title
FROM mytable
WHERE group_id = 10;

现在我想以每块 1000 块的形式查询相同的数据,以便更容易记忆:

SELECT id, row_number() over (ORDER BY id desc) AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 0 AND id < 1000
ORDER BY id ASC;

此处 row_number 从每个块的 1 重新开始,但我希望它就像第一种情况一样是全局查询的一部分。有没有简单的方法可以做到这一点?

您想查询前 1000 行,然后查询下 1000 行,依此类推?

通常您只需编写一个查询(您已经使用的查询),让您的应用获取 1000 条记录,对它们进行处理,然后获取下 1000 条,依此类推。因此不需要单独查询。

但是,编写这样的部分查询会相当容易:

select *
from
(
  SELECT id, row_number() over (ORDER BY id desc) AS rn, title
  FROM mytable
  WHERE group_id = 10
) numbered
where rn between 1 and 1000; -- <- simply change the row number range here
                             --    e.g. where rn between 1001 and 2000 for the second chunk

您需要分页。试试这个

SELECT id, row_number() over (ORDER BY id desc)+0 AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 0 AND id < 1000
ORDER BY id ASC;

下次,当您在 WHERE 子句中更改 id 的起始值时,请在 row_number() 中更改它,如下所示

SELECT id, row_number() over (ORDER BY id desc)+1000 AS row_number, title
FROM mytable
WHERE group_id = 10 AND id >= 1000 AND id < 2000
ORDER BY id ASC;

或者更好的是你可以使用 OFFSET 和 LIMIT 方法进行分页 https://wiki.postgresql.org/images/3/35/Pagination_Done_the_PostgreSQL_Way.pdf

最后我是这样做的:

首先我创建了一个临时物化视图:

CREATE MATERIALIZED VIEW vw_temp AS SELECT id, row_number() over (ORDER BY id desc) AS rn, title
FROM mytable
WHERE group_id = 10;

然后我定义索引:

CREATE INDEX idx_temp ON vw_temp USING btree(id);

现在我可以非常快速地执行所有操作,并且使用编号行:

SELECT * FROM vw_temp WHERE id BETWEEN 1000 AND 2000;

完成操作后,清理:

DROP INDEX idx_temp;
DROP MATERIALIZED VIEW vw_temp;

尽管 Thorsten Kettner 的回答似乎是最干净的,但由于太慢,对我来说并不实用。感谢大家的贡献。对于那些对实际用例感兴趣的人,我用它来将数据提供给 Sphinx 索引器。

假设:

  • id 定义为 PRIMARY KEY - 即 UNIQUENOT NULL。否则您可能必须处理 NULL 值和/或重复项(关系)。

  • 您在 table 上没有并发写入权限 - 或者您不关心拍摄快照后发生的情况。

一个MATERIALIZED VIEW, like you demonstrate ,是个不错的选择。

CREATE MATERIALIZED VIEW mv_temp AS
SELECT row_number() OVER (ORDER BY id DESC) AS rn, id, title
FROM   mytable
WHERE  group_id = 10;

但是索引和后续查询必须在行号rn上才能得到

data in chunks of 1000

CREATE INDEX ON mv_temp (<b>rn</b>);

SELECT * FROM mv_temp WHERE <b>rn</b> BETWEEN 1000 AND 2000;

您的实施将需要保证无间隙的 id 列 - 这将不需要添加行号以 ...

开头

完成后:

DROP MATERIALIZED VIEW mv_temp;

索引随 table(在本例中为物化视图)自动消失。

相关,更详细: