确定目标记录在 Postgres 查询中的偏移量
Determine a target record's offset in a Postgres query
问题: 我正在 Postgres 之上构建一个 RESTful API,其中包括以下参数:
- table
中特定记录的标识符 <id>
- 筛选和排序参数(可选)
count
或页面大小(可选)
例如:/presidents/16?filter=!isAlive&sort=lastName,givenNames&count=5
API returns count
(或可能更少)包含由 <id>
和 offset
和 [=13= 指定的记录的记录] 返回的记录。
在上面的示例中,结果可能如下所示:
{
"count": 5,
"offset": 20,
"records": [
{ "id": 17, "givenNames": "Andrew", "lastName": "Johnson", "isAlive": false },
{ "id": 36, "givenNames": "Lyndon B.", "lastName": "Johnson", "isAlive": false },
{ "id": 35, "givenNames": "John F.", "lastName": "Kennedy", "isAlive": false },
{ "id": 16, "givenNames": "Abraham", "lastName": "Lincoln", "isAlive": false },
{ "id": 4, "givenNames": "James", "lastName": "Madison", "isAlive": false }
]
}
当前解决方案:我目前的方法是连续进行三个调用(将它们组合成一个嵌套查询,但效率问题仍然存在),我正在寻找一个更好的方法。
获取目标 <id>
引用的记录,用于查询 #2。
- 例如
select * from presidents where id = 16
获取目标的偏移量<id>
- 例如
select count(*) from presidents where lastName < 'Lincoln' and givenNames < 'Abraham' and not isAlive order by lastName, givenNames, id
在计算出适当的 offset
和 limit
之后,使用传递的(或默认的)count
和来自 #2 的 count(*)
,检索记录页。
- 例如
select * from presidents where not isAlive order by lastName, givenNames, id offset 20 limit 5
已更新SQL
我采用了@ErwinBrandstetter 在他下面的回答中提供的内容,这与我在怪物声明中寻找的内容很接近,并将其更改为:
WITH prez AS (SELECT lastName, givenNames, id, isAlive FROM presidents WHERE not isAlive),
cte AS (SELECT * FROM prez WHERE id = 16),
start AS (SELECT (COUNT(*)/5)*5 as "offset" FROM prez WHERE (lastName, givenNames, id, isAlive) < (TABLE cte))
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT * FROM start) AS "offset"
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT * from prez
ORDER BY lastName, givenNames, id
OFFSET (SELECT * from start) LIMIT 5
) sub1
) sub2;
在 Postgres 中是否有更简单的方法来确定给定查询的给定记录的偏移量?
相关问题:
- getting the offset of a record in mysql query
- MySql Determine A Row Offset From a Query Result
您正在寻找的一站式商店:
WITH cte AS (SELECT lastName, givenNames, id AS x FROM presidents WHERE id = 16)
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT count(*) FROM presidents
WHERE (lastName, givenNames, id) < (TABLE cte)) AS "offset"
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT id, givenNames, lastName, isAlive
FROM presidents
WHERE (lastName, givenNames, id) >= (TABLE cte)
ORDER BY lastName, givenNames, id
LIMIT 5
) sub1
) sub2;
您的原始查询 #2 不正确:
SELECT * FROM presidents
WHERE lastName < 'Lincoln'
AND givenNames < 'Abraham'
AND id < 16 ...
要保留您的排序顺序,它必须是:
SELECT * FROM presidents
WHERE (lastName, givenNames, id) < ('Lincoln', 'Abraham', 16) ...
比较行类型,而不是在各个列上进行 AND-ing 表达式,这会产生完全不同的结果。这就是 ORDER BY
有效运作的方式。
除了 id
上的 PRIMARY KEY
之外,您还应该在 (lastName, givenNames, id)
上有一个 multicolumn index,才能使这个 快速 。
在 CTE 中具有 row_number()
的变体
根据您更新后的要求。
WITH prez AS (
SELECT lastName, givenNames, id, isAlive
, row_number() OVER (ORDER BY lastName, givenNames, id) AS rn
FROM presidents
WHERE NOT isAlive
)
, x AS (SELECT ((rn-1)/5)*5 AS "offset" FROM prez WHERE id = 16)
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT "offset" FROM x)
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT lastName, givenNames, id, isAlive
FROM prez
WHERE rn > (SELECT "offset" FROM x)
ORDER BY rn
LIMIT 5
) sub1
) sub2;
使用 EXPLAIN ANALYZE
测试性能。
问题: 我正在 Postgres 之上构建一个 RESTful API,其中包括以下参数:
- table 中特定记录的标识符
- 筛选和排序参数(可选)
count
或页面大小(可选)
<id>
例如:/presidents/16?filter=!isAlive&sort=lastName,givenNames&count=5
API returns count
(或可能更少)包含由 <id>
和 offset
和 [=13= 指定的记录的记录] 返回的记录。
在上面的示例中,结果可能如下所示:
{
"count": 5,
"offset": 20,
"records": [
{ "id": 17, "givenNames": "Andrew", "lastName": "Johnson", "isAlive": false },
{ "id": 36, "givenNames": "Lyndon B.", "lastName": "Johnson", "isAlive": false },
{ "id": 35, "givenNames": "John F.", "lastName": "Kennedy", "isAlive": false },
{ "id": 16, "givenNames": "Abraham", "lastName": "Lincoln", "isAlive": false },
{ "id": 4, "givenNames": "James", "lastName": "Madison", "isAlive": false }
]
}
当前解决方案:我目前的方法是连续进行三个调用(将它们组合成一个嵌套查询,但效率问题仍然存在),我正在寻找一个更好的方法。
获取目标
<id>
引用的记录,用于查询 #2。- 例如
select * from presidents where id = 16
- 例如
获取目标的偏移量
<id>
- 例如
select count(*) from presidents where lastName < 'Lincoln' and givenNames < 'Abraham' and not isAlive order by lastName, givenNames, id
- 例如
在计算出适当的
offset
和limit
之后,使用传递的(或默认的)count
和来自 #2 的count(*)
,检索记录页。- 例如
select * from presidents where not isAlive order by lastName, givenNames, id offset 20 limit 5
- 例如
已更新SQL
我采用了@ErwinBrandstetter 在他下面的回答中提供的内容,这与我在怪物声明中寻找的内容很接近,并将其更改为:
WITH prez AS (SELECT lastName, givenNames, id, isAlive FROM presidents WHERE not isAlive),
cte AS (SELECT * FROM prez WHERE id = 16),
start AS (SELECT (COUNT(*)/5)*5 as "offset" FROM prez WHERE (lastName, givenNames, id, isAlive) < (TABLE cte))
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT * FROM start) AS "offset"
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT * from prez
ORDER BY lastName, givenNames, id
OFFSET (SELECT * from start) LIMIT 5
) sub1
) sub2;
在 Postgres 中是否有更简单的方法来确定给定查询的给定记录的偏移量?
相关问题:
- getting the offset of a record in mysql query
- MySql Determine A Row Offset From a Query Result
您正在寻找的一站式商店:
WITH cte AS (SELECT lastName, givenNames, id AS x FROM presidents WHERE id = 16)
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT count(*) FROM presidents
WHERE (lastName, givenNames, id) < (TABLE cte)) AS "offset"
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT id, givenNames, lastName, isAlive
FROM presidents
WHERE (lastName, givenNames, id) >= (TABLE cte)
ORDER BY lastName, givenNames, id
LIMIT 5
) sub1
) sub2;
您的原始查询 #2 不正确:
SELECT * FROM presidents
WHERE lastName < 'Lincoln'
AND givenNames < 'Abraham'
AND id < 16 ...
要保留您的排序顺序,它必须是:
SELECT * FROM presidents
WHERE (lastName, givenNames, id) < ('Lincoln', 'Abraham', 16) ...
比较行类型,而不是在各个列上进行 AND-ing 表达式,这会产生完全不同的结果。这就是 ORDER BY
有效运作的方式。
除了 id
上的 PRIMARY KEY
之外,您还应该在 (lastName, givenNames, id)
上有一个 multicolumn index,才能使这个 快速 。
在 CTE 中具有 row_number()
的变体
根据您更新后的要求。
WITH prez AS (
SELECT lastName, givenNames, id, isAlive
, row_number() OVER (ORDER BY lastName, givenNames, id) AS rn
FROM presidents
WHERE NOT isAlive
)
, x AS (SELECT ((rn-1)/5)*5 AS "offset" FROM prez WHERE id = 16)
SELECT row_to_json(sub2) AS js
FROM (
SELECT (SELECT "offset" FROM x)
, count(*) AS "count"
, array_agg(sub1) AS records
FROM (
SELECT lastName, givenNames, id, isAlive
FROM prez
WHERE rn > (SELECT "offset" FROM x)
ORDER BY rn
LIMIT 5
) sub1
) sub2;
使用 EXPLAIN ANALYZE
测试性能。