根据行ID查找排序中的行号,然后查找其邻居

Pie*_*aud 5 sql firebird sql-order-by rowcount rank

说我有一些SELECT陈述:

SELECT id, name FROM people
   ORDER BY name ASC;
Run Code Online (Sandbox Code Playgroud)

我在people表中有几百万行,该ORDER BY子句可能比我在这里显示的要复杂得多(可能在十几列上运行).

我只检索行的一小部分(比如行1..11),以便在UI中显示它们.现在,我想解决以下问题:

  1. 找到给定的行数id.
  2. 显示之前的5个项目和连续的5个项目id.

一旦我解决了问题1,问题2很容易解决,因为如果我知道我要查找的项目1000在排序结果集中有行号(这是Firebird SQL方言),我就可以使用这样的东西:

SELECT id, name FROM people
   ORDER BY name ASC
   ROWS 995 TO 1005;
Run Code Online (Sandbox Code Playgroud)

我也知道,我能找到的等级通过计算所有一个我找前落入排了一排,但是这可能会导致很长的WHERE从句用吨ORAND在状态.我必须反复这样做.使用我的测试数据,即使使用正确索引的列,这也需要数百毫秒,这太慢了.

是否有一些方法可以通过使用一些SQL:2003功能(如row_numberFirebird 3.0支持)来实现这一目的?我绝不是一个SQL大师,我需要一些指针.我可以创建一个缓存视图,其结果将包括排名/密集排名/行索引?

Gor*_*off 3

Firebird 似乎支持窗口函数(在 Oracle 中称为分析函数)。因此您可以执行以下操作:

要查找具有给定 id 的行的“行”号:

select id, row_number() over (partition by NULL order by name, id)
from t
where id = <id>
Run Code Online (Sandbox Code Playgroud)

这假设 id 是唯一的。

解决第二个问题:

select t.*
from (select id, row_number() over (partition by NULL order by name, id) as rownum
      from t
     ) t join 
     (select id, row_number() over (partition by NULL order by name, id) as rownum
      from t
      where id = <id>
     ) tid
     on t.rownum between tid.rownum - 5 and tid.rownum + 5
Run Code Online (Sandbox Code Playgroud)

不过,如果您可以修改表结构,我可能会提出其他建议。大多数数据库都提供在插入行时添加自动增量列的功能。如果您的记录从未被删除,这可以作为您的计数器,简化您的查询。