高效 SQL 查找用于分页的特定 ID
Efficient SQL to find specific ID used with pagination
在工作中,我需要在 API 中实现一项功能,即 returns 包含具有指定 ID 的条目的特定页面(20 个条目)。该条目可以是页面中这 20 个条目中的任何一个。
通常情况下,一个页面是通过获取上一页的最后一个元素的ID,对前一个ID之后的元素应用过滤器并取结果的前20个条目来确定的。
但是使用新功能,您应该收到包含指定 ID 的页面,而不是使用它来确定新页面的第一个元素。
我与数据库打交道的不多,所以我不确定,但由于我是这家公司唯一的开发人员,所以没有人可以问。如果有帮助,数据库是 MS SQL Server。如果需要更多信息,我可以提供,只要不违反公司政策。
如果我理解你的问题,你的页面大小固定为每页 20 条记录。您将收到一个 ID 值,该 ID 值可以出现在包含 20 条记录的给定页面上的任何位置。因此,假设 ID 值从 1 开始,如果您收到一个介于 1 和 20 之间的 ID 值,它应该 return 第 1 页上的所有记录,如果收到的 ID 值介于 21 和 40 之间,它应该 return 第2页等所有记录
我们可以通过整数除法计算出我们所在的页面 - ID 除以 20,然后加 1。因此对于 ID 4,(4 / 20) 为零(记住整数除法!)然后添加1 获取第 1 页。您可以使用 SQL 服务器的 LIMIT...OFFSET
功能(假设您使用的是支持它的版本)。
我将创建一个简单的脚本来展示它是如何工作的。我不知道您是打算创建一个存储过程还是什么,但是您可以采用这种技术。因此,让我们制作一个简单的 table 变量来模仿您的 table,为一些示例数据添加 100 条记录,然后编写查询以在适当的页面上检索记录。
-- create a table for the query
DECLARE @Records AS TABLE(
ID INT IDENTITY(1,1) NOT NULL,
[Value] INT NOT NULL
);
-- populate with 100 sample records
DECLARE @i INT;
SELECT @i = 1;
WHILE (@i <= 100)
BEGIN
INSERT INTO @Records([Value]) VALUES (@i);
SELECT @i = @i + 1;
END
-- now find the records on the correct page
DECLARE @id INT = 41; -- the record to find
DECLARE @pageSize INT = 20; -- the number of records per page
DECLARE @page INT; -- the page, counting from 1
SELECT @page = (@id / 20) + 1;
SELECT ID, [Value]
FROM @Records
ORDER BY ID
OFFSET (@page -1 ) * @pageSize ROWS
FETCH NEXT @pageSize ROWS ONLY;
这应该适合你(如果我明白你在问什么)。
假设我们要查找 ID 123456。这可以是从第 1 页到第 6173 页的任何位置(甚至完全缺失)。在我们到达那里之前,除了计算 rows/pages 之外别无他法。我们甚至必须指望获得仍在同一页上的所有后续行。这个不难,就是比较慢
我们无法知道哪个ID接踵而至;在 ID 5 之后,下一个可能是 ID 6 或 1234 或 1000000 或其他。所以第一步是对所有按 ID 排序的行进行编号。或者更确切地说,为它们分配页面,因为我们知道数字 1 到 20 = 第 1 页,数字 21 到 40 = 第 2 页,等等。因此我们知道我们的 ID 在第 X 页上,我们必须 select 所有标记的行第 X 页。
with rows_with_page as
(
select
t.*,
(row_number() over (order by id) - 1) / 20 + 1 as page
from mytable t
)
select *
from rows_with_page
where page = (select page from rows_with_page where id = @id)
order by id;
由于行号是一个整数,/
除法是一个整数除法,在SQL服务器中得到一个整数(如小学;5 / 2 = 2)。
在工作中,我需要在 API 中实现一项功能,即 returns 包含具有指定 ID 的条目的特定页面(20 个条目)。该条目可以是页面中这 20 个条目中的任何一个。
通常情况下,一个页面是通过获取上一页的最后一个元素的ID,对前一个ID之后的元素应用过滤器并取结果的前20个条目来确定的。
但是使用新功能,您应该收到包含指定 ID 的页面,而不是使用它来确定新页面的第一个元素。
我与数据库打交道的不多,所以我不确定,但由于我是这家公司唯一的开发人员,所以没有人可以问。如果有帮助,数据库是 MS SQL Server。如果需要更多信息,我可以提供,只要不违反公司政策。
如果我理解你的问题,你的页面大小固定为每页 20 条记录。您将收到一个 ID 值,该 ID 值可以出现在包含 20 条记录的给定页面上的任何位置。因此,假设 ID 值从 1 开始,如果您收到一个介于 1 和 20 之间的 ID 值,它应该 return 第 1 页上的所有记录,如果收到的 ID 值介于 21 和 40 之间,它应该 return 第2页等所有记录
我们可以通过整数除法计算出我们所在的页面 - ID 除以 20,然后加 1。因此对于 ID 4,(4 / 20) 为零(记住整数除法!)然后添加1 获取第 1 页。您可以使用 SQL 服务器的 LIMIT...OFFSET
功能(假设您使用的是支持它的版本)。
我将创建一个简单的脚本来展示它是如何工作的。我不知道您是打算创建一个存储过程还是什么,但是您可以采用这种技术。因此,让我们制作一个简单的 table 变量来模仿您的 table,为一些示例数据添加 100 条记录,然后编写查询以在适当的页面上检索记录。
-- create a table for the query
DECLARE @Records AS TABLE(
ID INT IDENTITY(1,1) NOT NULL,
[Value] INT NOT NULL
);
-- populate with 100 sample records
DECLARE @i INT;
SELECT @i = 1;
WHILE (@i <= 100)
BEGIN
INSERT INTO @Records([Value]) VALUES (@i);
SELECT @i = @i + 1;
END
-- now find the records on the correct page
DECLARE @id INT = 41; -- the record to find
DECLARE @pageSize INT = 20; -- the number of records per page
DECLARE @page INT; -- the page, counting from 1
SELECT @page = (@id / 20) + 1;
SELECT ID, [Value]
FROM @Records
ORDER BY ID
OFFSET (@page -1 ) * @pageSize ROWS
FETCH NEXT @pageSize ROWS ONLY;
这应该适合你(如果我明白你在问什么)。
假设我们要查找 ID 123456。这可以是从第 1 页到第 6173 页的任何位置(甚至完全缺失)。在我们到达那里之前,除了计算 rows/pages 之外别无他法。我们甚至必须指望获得仍在同一页上的所有后续行。这个不难,就是比较慢
我们无法知道哪个ID接踵而至;在 ID 5 之后,下一个可能是 ID 6 或 1234 或 1000000 或其他。所以第一步是对所有按 ID 排序的行进行编号。或者更确切地说,为它们分配页面,因为我们知道数字 1 到 20 = 第 1 页,数字 21 到 40 = 第 2 页,等等。因此我们知道我们的 ID 在第 X 页上,我们必须 select 所有标记的行第 X 页。
with rows_with_page as
(
select
t.*,
(row_number() over (order by id) - 1) / 20 + 1 as page
from mytable t
)
select *
from rows_with_page
where page = (select page from rows_with_page where id = @id)
order by id;
由于行号是一个整数,/
除法是一个整数除法,在SQL服务器中得到一个整数(如小学;5 / 2 = 2)。