Postgres 9.1データベースには次のテーブル構造がありますが、理想的なソリューションは、可能であればDBに依存しないことです。
表:users | id | username | | 1 | one | | 2 | two | | 3 | three | 表:items | id | userid | itemname | created | | 1 | 1 | a |タイムスタンプ| | 2 | 1 | b |タイムスタンプ| | 3 | 1 | c |タイムスタンプ| | 4 | 2 | d |タイムスタンプ| | 5 | 2 | e |タイムスタンプ| | 6 | 2 | f |タイムスタンプ| | 7 | 3 | g |タイムスタンプ| | 8 | 3 | h |タイムスタンプ| | 9 | 3 | i |タイムスタンプ|
次と前のitem.idを提供するクエリ(ビュー用)があります。
例えば.
表示:UserItems | id | userid | itemname | nextitemid | previtemid | created | | 1 | 1 | a | 2 | null | timestamp | | 2 | 1 | b | 3 | 1 |タイムスタンプ| | 3 | 1 | c | 4 | 2 |タイムスタンプ| | 4 | 2 | d | 5 | 3 |タイムスタンプ| | 5 | 2 | e | 6 | 4 |タイムスタンプ| | 6 | 2 | f | 7 | 5 |タイムスタンプ| | 7 | 3 | g | 8 | 6 |タイムスタンプ| | 8 | 3 | h | 9 | 7 |タイムスタンプ| | 9 | 3 | i | null | 8 |タイムスタンプ|
私は次のクエリでこれを行うことができます:
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)IDをラップさせる方法はありますか?.
2)ユーザーIDで次と前のアイテムIDをグループ化するパフォーマンスの高い方法はありますか?.
注意: この例では、ユーザーのitemidはシーケンシャルですが、実際のデータの場合はそうではなく、各ユーザーのitemidはインターリーブされています。
表示:UserItems | id | userid | itemname | nextitemid | previtemid | nextuseritemid | prevuseritemid | created | | 1 | 1 | a | 2 | 9 | 2 | 3 |タイムスタンプ| | 2 | 1 | b | 3 | 1 | 3 | 1 |タイムスタンプ| | 3 | 1 | c | 4 | 2 | 1 | 2 |タイムスタンプ| | 4 | 2 | d | 5 | 3 | 5 | 6 |タイムスタンプ| | 5 | 2 | e | 6 | 4 | 6 | 4 |タイムスタンプ| | 6 | 2 | f | 7 | 5 | 4 | 5 |タイムスタンプ| | 7 | 3 | g | 8 | 6 | 8 | 9 |タイムスタンプ| | 8 | 3 | h | 9 | 7 | 9 | 7 |タイムスタンプ| | 9 | 3 | i | 1 | 8 | 7 | 8 |タイムスタンプ|
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;
updatePostgreSQLでは first_value関数とlast_value関数 を忘れてしまいました。dnoethのおかげで、彼はそれについて私に思い出させました。ただし、last_value
がデフォルトウィンドウで機能しているため、彼のクエリは機能していません 境界のない前の行と現在の行の間の範囲 正しい結果を返さないため、範囲内で範囲を変更する必要があります句を使用するか、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;