sql - 分页使用搜索方法(键集)

标签 sql node.js database postgresql pagination

我有关于如何使用搜索方法进行分页的问题,
在我的查询中,我需要
1.对多列进行排序
2.某些列不唯一

例如,如果数据如下所示,并执行查询 select * from ... order by name asc, status asc ....(other column), id asc 并得到 8 1 3 10 2 5 6 7 9 4
现在如果我想做分页,每次选择 2 行, 第一页与上面的查询相同,只需添加限制 2 select * from ... order by name asc, status asc ....(other column), id asc
如何选择下一页?

如果只是 id 列我知道它是检查顺序,如果 asc 然后找到比以前结果中最大的 id 更大的 id。
但是,如果列是多个列并且某些列不是唯一值,如何解决?

id | name | status | ...
1 b 0
2 b 0
3 b 0
4 j 0
5 f 0
6 g 0
7 h 0
8 a 0
9 i 0
10 b 0

问题 1。

// example table
CREATE TABLE IF NOT EXISTS "table"(
    "id" SERIAL NOT NULL,
    "create_date" timestamp without time zone NOT NULL,
    "create_by_user_id" integer NOT NULL,
    "last_modified_date" timestamp without time zone DEFAULT NULL,
    "last_modified_by_user_id" integer DEFAULT NULL,
    "url_id" varchar(50) NOT NULL,
    "status" integer NOT NULL,
    "rank" integer NOT NULL,
    "name" varchar DEFAULT NULL,
    "name_slug" varchar DEFAULT NULL,
    "description" varchar DEFAULT NULL,
    "start_date" date NOT NULL,
    "end_date" date NOT NULL,
    PRIMARY KEY ("id"),
    UNIQUE ("url_id"),
    FOREIGN KEY ("create_by_user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
  );

// select first page
SELECT * FROM table 
  ORDER BY name ASC NULLS LAST
   , status ASC NULLS LAST
   , rank DESC NULLS LAST
   , id ASC
  LIMIT 2;

// select next page  How do I know use <, >, <=, >= in below ?
SELECT * FROM table
  WHERE name ?? operator prev_end_name
    AND  status ??  prev_end_status
    AND  rank ??  prev_end_rank
    AND  id ?? prev_end_id
  ORDER BY name ASC NULLS LAST
   , status ASC NULLS LAST
   , rank DESC NULLS LAST
   , id ASC
  LIMIT 2;

我做了一些研究,我在网上发现的所有相关帖子都显示使用以前的 id 的相同内容......但在现实生活中如何使它按不同的多列排序?像 instagram api 也使用以前的 id 但如何按许多其他列进行排序和排序..
http://use-the-index-luke.com/sql/partial-results/fetch-next-page
http://leopard.in.ua/2014/10/11/postgresql-paginattion
https://blog.jooq.org/2013/10/26/faster-sql-paging-with-jooq-using-the-seek-method/
https://www.citusdata.com/blog/2016/03/30/five-ways-to-paginate/
https://www.reddit.com/r/programming/comments/2crwyg/we_need_tool_support_for_keyset_pagination/

请不要提供使用页码设置分页偏移限制的方式,这不是我要找的。

问题 2.
我正在用 node.js 做这件事,
不使用任何查询生成器 orm 库,
我的模型的一部分构建了如下查询,
所以如果需要对很多列进行排序,很难添加 seek 方法。
想知道人们通常如何在现实生活中的大型站点 nodejs + postgres 应用程序中做到这一点, 任何建议将不胜感激!

if (typeof request.data.query.pagination_type != 'undefined') {
  if (request.data.query.pagination_type == 'seek') {
    if (typeof request.data.query.sort_order_list != 'undefined') {
      for (var i = 0; i < request.data.query.sort_order_list.length; i++) {
        if (request.data.query.sort_order_list[i].sort == 'name') {
          if (typeof request.data.query.prev_end_name != 'undefined') {
            if (!start) { dbQuery += ' AND'; } else { dbQuery += ' WHERE'; }
            if (start) { start = false; }
            if (request.data.query.sort_order_list[i].order == 'asc') {
              dbQuery += ` ee.name < $` + paramsIndex;
            } else if (request.data.query.sort_order_list[i].order == 'desc') {
              dbQuery += ` ee.name > $` + paramsIndex;
            }
            paramsIndex++;
            dbParams.push(request.data.query.prev_end_name);
          }
        } else if (request.data.query.sort_order_list[i].sort == 'start_date') {
...

查询输出类似

SELECT t.* 
  FROM task t WHERE 
  t.status = $1 
  AND t.rank >= $2 
  AND t.end_date >= $3 
  AND t.rank < $4 
  AND t.end_date < $5 
  AND t.name < $6 
  AND t.start_date > $7 
  ORDER BY t.rank asc NULLS LAST, 
    t.end_date asc NULLS LAST, 
    t.name asc NULLS LAST, 
    t.start_date desc NULLS LAST LIMIT $8

最佳答案

Seek 方法需要一个唯一的列来排序。如果你想按状态升序排序,你要做的是这样的:

SELECT t.* 
  FROM task t WHERE 
  t.status = $1 
  AND t.rank >= $2 
  AND t.end_date >= $3 
  AND t.rank < $4 
  AND t.end_date < $5 
  AND t.name < $6 
  AND t.start_date > $7 
  ORDER BY t.status asc NULLS LAST, 
    t.id asc NULLS LAST
LIMIT $8

这将为您提供一个按状态排序的页面,如果状态相同,则按 ID 排序。您可以使用 N 列来执行此操作,请始终记住将 ID 放在最后。

为了检索下一页,您需要最后一个项目的状态/ID,查询类似于:

SELECT t.* 
  FROM task t WHERE 
  t.status = $1 
  AND t.rank >= $2 
  AND t.end_date >= $3 
  AND t.rank < $4 
  AND t.end_date < $5 
  AND t.name < $6 
  AND t.start_date > $7

--Pagination Where Clause
  AND t.status > $9
  OR (t.status = $9 AND t.id > $10)
 
  ORDER BY t.status asc NULLS LAST, 
    t.id asc NULLS LAST
LIMIT $8

其中 $9 是最后一项的状态,$10 是最后一项的 ID(来自上一页)。 >更改为 <如果您想按 DESC 排序,请在分页 where 子句上。

关于sql - 分页使用搜索方法(键集),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41404593/

相关文章:

java - 如何使用 JdbcTemplate 获取数组形式的结果?

Javascript Promises 显式函数与内联函数

node.js - 无法通过 sidecar 使用外部 API 让 falcor 路由器引用数据

mysql - mysql中的存储过程语法

c# - 使 SQL Server 中的正则表达式搜索更高效

mysql - 如何保持自动增量批量加载

mysql - 使用 Express 更改回调内的 session 对象

database - 在数据库上强制字段唯一性是一个糟糕的设计

mysql - 将 mysql 数据库转换为 Oracle

mysql - 我如何在JavaFX中进行异步数据库