我有一个表格(简化为极端以使其更清晰)
create table mytable (
id integer not null,
owner text not null,
order_field_1 integer not null,
order_field_2 integer not null
)
每次从数据库中获取一行时,我都试图获取下一个和前一个元素的ID,以允许导航。这些行不是按ID排序,而是按ORDER BY order_field_1 DESC, order_field_2 DESC
排序。
获取所有者的最后一个条目时,使用窗口和超前/滞后来找到我想要的内容是没有问题的
SELECT
id,
owner,
lag(id) over w AS previous_id,
lead(id) over w AS next_id
FROM
mytable
WHERE
owner = 'someuser'
WINDOW w AS (
ORDER BY order_field_1 DESC,
order_field_2 DESC
)
ORDER BY
order_field_1 DESC,
order_field_2 DESC
LIMIT
5
这是从记忆中写出的,但这是它的要点,而且效果很好。
我的问题是,当我想使用所有者AND id获取特定行时,我仍然想要找到上一个和下一个id,我不能再使用窗口函数了,因为where只返回一行,我当前做一个子查询以获得两个导航ID的解决方案并不是很好的性能
例如(我只放了以前的id,因为下一个是相同的)
SELECT
m1.id,
m1.owner,
(
SELECT
m2.id
FROM
mytable m2
WHERE
m2.owner = m1.owner
AND m2.id != m1.id
AND (
m2.order_field_1 < m1.order_field_1
OR (
m2.order_field_1 = m1.order_field_1
AND m2.order_field_2 <= m1.order_field_2
)
ORDER BY
m2.order_field_1 DESC,
m2.order_field_2 DESC
LIMIT
1
) AS previous_id
FROM
mytable m1
WHERE
owner = 'someuser'
AND id = 12345
所以我选择了我的行,然后从同一个用户中选择第一行,使用不同的id,即使用较低的order_field_1或相同但较低的order_field_2。
这不是很有效率,我的表现很糟糕,我想知道是否有人对如何改进它有任何想法?
例子数据集:
id | owner | order_field_1 | order_field_2
1 | someuser | 4 | 2
2 | someuser | 2 | 8
3 | someuser | 4 | 3
4 | someuser | 3 | 2
5 | someuser | 4 | 6
6 | someuser | 4 | 5
序:
id | owner | order_field_1 | order_field_2
5 | someuser | 4 | 6
6 | someuser | 4 | 5
3 | someuser | 4 | 3
1 | someuser | 4 | 2
4 | someuser | 3 | 2
2 | someuser | 2 | 8
如果我选择owner ='someuser'且id = 3,则previous_id应为1,next_id应为6。
如果我选择owner ='someuser'且id = 1,则previous_id应为4,next_id应为3。
提前感谢您提供任何帮助
答案 0 :(得分:2)
在CTE中WHERE owner = 'someuser'
已经多了:
WITH t AS (
SELECT id
,owner
,lag(id) over w AS previous_id
,lead(id) over w AS next_id
FROM mytable
WHERE owner = 'someuser'
WINDOW w AS (ORDER BY order_field_1 DESC, order_field_2 DESC)
)
SELECT *
FROM t
WHERE id = 3
此外,由于您只选择一行,因此最终ORDER BY
中无需SELECT
。
__
它相当丑陋,但如果每个owner
有很多行可能会更快。你必须测试......
SELECT id
, owner
,(SELECT id
FROM tbl p
WHERE p.owner = t.owner -- same owner
AND p.id <> t.id -- different id
AND p.order_field_1 <= t.order_field_1
AND p.order_field_2 <= t.order_field_2
ORDER BY order_field_1 DESC
, order_field_2 DESC
LIMIT 1) AS previous_id
,(SELECT id
FROM tbl n
WHERE n.owner = t.owner
AND n.id <> t.id
AND n.order_field_1 >= t.order_field_1
AND n.order_field_2 >= t.order_field_2
ORDER BY order_field_1
, order_field_2
LIMIT 1) AS next_id
FROM tbl t
WHERE owner = 'someuser'
AND id = 3
这个也适用于旧版本的PostgreSQL 当然,性能的关键是适当的索引。
答案 1 :(得分:1)
在应用WHERE子句之前如何找到滞后和超前值?
WITH T as (
SELECT
id,
owner,
lag(id) over w AS previous_id,
lead(id) over w AS next_id
FROM
mytable
WINDOW w AS (
ORDER BY order_field_1 DESC,
order_field_2 DESC
)
)
SELECT * FROM T
WHERE
owner = 'someuser' AND id = 3
ORDER BY
order_field_1 DESC,
order_field_2 DESC