【发布时间】:2014-12-17 04:05:53
【问题描述】:
编辑: 我使用的原始示例有一个 int 作为主键,而实际上我的主键是一个包含 UUID 作为字符串的 var char。我已更新以下问题以反映这一点。
警告:解决方案必须适用于 postgres。
问题:从已知页码或索引到要分页的结果列表中时,我可以轻松地对数据进行分页,但如果我只知道该行的主键,如何做到这一点从开始。例如说我的表有这些数据
TABLE: article
======================================
id categories content
--------------------------------------
B7F79F47 local a
6cb80450 local b
563313df local c
9205AE5A local d
E88F7520 national e
5ab669a5 local f
fb047cf6 local g
591c6b50 national h
======================================
给定文章主键“9205AE5A”(article.id == '9205AE5A'),并且类别列必须包含“本地”,如果它是分页的,即返回的结果应该包含 3 个项目(上一篇、当前、下一篇)
('563313df','local','c'),('9205AE5A','local','d'),('5ab669a5','local','f')
这是我的示例设置:
-- setup test table and some dummy data
create table article (
id varchar(36),
categories varchar(256),
content varchar(256)
)
insert into article values
('B7F79F47', 'local', 'a'),
('6cb80450', 'local', 'b'),
('563313df', 'local', 'c'),
('9205AE5A', 'local', 'd'),
('E88F7520', 'national', 'e'),
('5ab669a5', 'local', 'f'),
('fb047cf6', 'local', 'g'),
('591c6b50', 'national', 'h');
我想对文章表中的行进行分页,但我的起点是文章的“id”。为了在呈现的页面上提供“上一篇文章”和“下一篇文章”链接,我还需要这篇文章两边的文章我知道
的 id在服务器端,我可以运行分页 sql 并遍历每个结果集以查找给定项目的索引。请参阅以下低效伪代码/sql 来执行此操作:
page = 0;
resultsPerPage = 10;
articleIndex = 0;
do {
resultSet = select * from article where categories like '%local%' limit resultsPerPage offset (page * resultsPerPage) order by content;
for (result in resultSet) {
if (result.id == '9205AE5A') {
// we have found the articles index ('articleIndex') in the paginated list.
// Now we can do a normal pagination to return the list of 3 items starting at the article prior to the one found
return select * from article where categories like '%local%' limit 3 offset (articleIndex - 1);
}
articleIndex++;
}
page++;
} while (resultSet.length > 0);
如果给定的文章在分页列表的下方,这将非常缓慢。如果没有丑陋的 while+for 循环,如何做到这一点?
编辑2:我可以使用两个sql调用得到结果
SELECT 'CurrentArticle' AS type,* FROM
(
SELECT (ROW_NUMBER() OVER (ORDER BY content ASC)) AS RowNum,*
FROM article
WHERE categories LIKE '%local%'
ORDER BY content ASC
) AS tagCloudArticles
WHERE id='9205AE5A'
ORDER BY content ASC
LIMIT 1 OFFSET 0
从该结果返回,例如
('CurrentArticle', 4, '9205AE5A', 'local', 'd')
我可以得到RowNum值(4)然后再次运行sql得到RowNum+1(5)和RowNum-1(3)
SELECT 'PrevNextArticle' AS type,* FROM
(
SELECT (ROW_NUMBER() OVER (ORDER BY content ASC)) AS RowNum,*
FROM article
WHERE categories LIKE '%local%'
ORDER BY content ASC
) AS tagCloudArticles
WHERE RowNum in (3, 5)
ORDER BY content ASC
LIMIT 2 OFFSET 0
结果
('PrevNextArticle', 3, '563313df', 'local', 'c'),
('PrevNextArticle', 5, '5ab669a5', 'local', 'f')
如果能在一个高效的 sql 调用中执行此操作会很好。
【问题讨论】:
-
那么订购标准是什么?内容?时间戳?一个集合是无序的。
-
在上面的示例中,我使用了“内容”,但实际上可以假设它是我未显示的任意数量的其他列,例如发布的时间戳、标签、作者、标题等。
-
@ShaneRowatt 我已经发布了答案。这是正确的还是我理解错了你的问题。
标签: sql postgresql pagination