[英]Postgres Next/Previous row SQL Query
我在Postgres 9.1数据库中有以下表结构,但如果可能,理想的解决方案应该是DB不可知的:
Table: users |id|username| |1 |one | |2 |two | |3 |three | Table: items |id|userid|itemname|created | |1 |1 |a |timestamp| |2 |1 |b |timestamp| |3 |1 |c |timestamp| |4 |2 |d |timestamp| |5 |2 |e |timestamp| |6 |2 |f |timestamp| |7 |3 |g |timestamp| |8 |3 |h |timestamp| |9 |3 |i |timestamp|
我有一个查询(视图),提供下一个和上一个item.id.
例如
View: UserItems |id|userid|itemname|nextitemid|previtemid|created | |1 |1 |a |2 |null |timestamp| |2 |1 |b |3 |1 |timestamp| |3 |1 |c |4 |2 |timestamp| |4 |2 |d |5 |3 |timestamp| |5 |2 |e |6 |4 |timestamp| |6 |2 |f |7 |5 |timestamp| |7 |3 |g |8 |6 |timestamp| |8 |3 |h |9 |7 |timestamp| |9 |3 |i |null |8 |timestamp|
我可以使用以下查询执行此操作:
SELECT
DISTINCT i.id AS id,
i.userid AS userid,
i.itemname AS itemname,
LEAD(i.id) OVER (ORDER BY i.created DESC) AS nextitemid,
LAG(i.id) OVER (ORDER BY i.created DESC) AS previtemid,
i.created AS created
FROM items i
LEFT JOIN users u
ON i.userid = u.id
ORDER BY i.created DESC;
你能帮忙解决以下问题吗:
1)有没有办法使ids包裹即
2)是否存在一种通过用户ID对下一个和前一个itemid进行分组的高效方法,例如
View: UserItems |id|userid|itemname|nextitemid|previtemid|nextuseritemid|prevuseritemid|created | |1 |1 |a |2 |9 |2 |3 |timestamp| |2 |1 |b |3 |1 |3 |1 |timestamp| |3 |1 |c |4 |2 |1 |2 |timestamp| |4 |2 |d |5 |3 |5 |6 |timestamp| |5 |2 |e |6 |4 |6 |4 |timestamp| |6 |2 |f |7 |5 |4 |5 |timestamp| |7 |3 |g |8 |6 |8 |9 |timestamp| |8 |3 |h |9 |7 |9 |7 |timestamp| |9 |3 |i |1 |8 |7 |8 |timestamp|
Q1:FIRST_VALUE / LAST_VALUE
Q2:PARTITION BY(正如Roman Pekar已经建议的那样)
SELECT
DISTINCT i.id AS id,
i.userid AS userid,
i.itemname AS itemname,
COALESCE(LEAD(i.id) OVER (ORDER BY i.created DESC)
,FIRST_VALUE(i.id) OVER (ORDER BY i.created DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) AS nextitemid,
COALESCE(LAG(i.id) OVER (ORDER BY i.created DESC)
,LAST_VALUE(i.id) OVER (ORDER BY i.created DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) AS previtemid,
COALESCE(LEAD(i.id) OVER (PARTITION BY i.userid ORDER BY i.created DESC)
,FIRST_VALUE(i.id) OVER (PARTITION BY i.userid ORDER BY i.created DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) AS nextuseritemid,
COALESCE(LAG(i.id) OVER (PARTITION BY i.userid ORDER BY i.created DESC)
,LAST_VALUE(i.id) OVER (PARTITION BY i.userid ORDER BY i.created DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)) AS prevuseritemid,
i.created AS created
FROM items i
LEFT JOIN users u
ON i.userid = u.id
ORDER BY i.created DESC;
更新我忘记了PostgreSQL中的first_value和last_value函数 ,多亏了他提醒我的dnoeth。 但是,他的查询不起作用,因为last_value
正在使用默认窗口RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW并且不会返回正确的结果,所以你要么必须改变over子句内的范围要么使用first_value
和order by asc
:
select
i.id as id,
i.userid as userid,
i.itemname as itemname,
coalesce(
lead(i.id) over(order by i.created desc),
first_value(i.id) over(order by i.created desc)
) as nextitemid,
coalesce(
lag(i.id) over(order by i.created desc),
first_value(i.id) over(order by i.created asc)
) as previtemid,
coalesce(
lead(i.id) over(partition by i.userid order by i.created desc),
first_value(i.id) over(partition by i.userid order by i.created desc)
) as nextuseritemid,
coalesce(
lag(i.id) over(partition by i.userid order by i.created desc),
first_value(i.id) over(partition by i.userid order by i.created asc)
) as prevuseritemid,
i.created as created
from items as i
left outer join users as u on u.id = i.userid
order by i.created desc
以前的版本
我想你可以这样做:
SELECT
i.id AS id,
i.userid AS userid,
i.itemname AS itemname,
coalesce(
LEAD(i.id) OVER (ORDER BY i.created DESC),
(select t.id from items as t order by t.created desc limit 1)
) AS nextitemid,
coalesce(
LAG(i.id) OVER (ORDER BY i.created DESC),
(select t.id from items as t order by t.created asc limit 1)
) AS previtemid,
coalesce(
LEAD(i.id) OVER (partition by i.userid ORDER BY i.created DESC),
(select t.id from items as t where t.userid = i.userid order by t.created desc limit 1)
) AS nextuseritemid,
coalesce(
LAG(i.id) OVER (partition by i.userid ORDER BY i.created DESC),
(select t.id from items as t where t.userid = i.userid order by t.created asc limit 1)
) AS prevuseritemid,
i.created AS created
FROM items i
LEFT JOIN users u
ON i.userid = u.id
ORDER BY i.created DESC;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.