获取 Where in 中每个元素的前一行
Get prior row for each element in Where in
我正在使用 PostgreSQL 数据库。
这里的想法:
- 一个用户可以玩一个游戏
- 每个游戏可以有1个或多个小游戏
- 每个小游戏都有一个结果
这里是数据库的种类:
id | user_id | game_id | mini_game_id | result | created_at
-----------------------------------------------------------
70 | 44 | 105 | 22 | 19 | 28/11/2016
69 | 44 | 105 | 20 | 18 | 28/11/2016
68 | 44 | 104 | 22 | 17 | 27/11/2016
67 | 44 | 104 | 21 | 16 | 27/11/2016
66 | 44 | 103 | 22 | 15 | 26/11/2016
65 | 44 | 103 | 21 | 14 | 26/11/2016
64 | 44 | 103 | 20 | 13 | 26/11/2016
我想在其最新游戏结束时显示每个 mini_game 的结果,以及前一个相同 mini_game 的结果。
需要的结果:
示例:对于 user 44
,在其 game 105
的末尾,我想获取此数据:
id | game_id | mini_game_id | second-to-last-result | date
-----------------------------------------------------------------
68 | 104 | 22 | 17 | 27/11/2016
64 | 103 | 20 | 13 | 26/11/2016
我尝试过的:
第一次尝试:
SELECT mini_game_id,
array_agg(result) as results,
array_agg(created_at) as dates
FROM result
WHERE user_id = 44
AND game_id != 105 --Exclude latest game
GROUP BY mini_game_id
ORDER BY mini_game_id
结果:
mini_game_id | results | dates
--------------------------------------------------
22 | {17, 15} | {27/11/2016, 26/11/2016}
21 | {16, 14} | {27/11/2016, 26/11/2016}
20 | {13} | {26/11/2016}
这里的问题是我为一个用户获取每个游戏的每个 mini_game 结果,这对我来说似乎太过分了,因为我可以有数千个结果...
第二次尝试:
SELECT id,
game_id,
mini_game_id,
result,
created_at
FROM result
WHERE user_id = 44
AND game_id != 105 --Exclude latest game
AND mini_game IN (22, 20) --The two mini-games the user have played in game 105
ORDER BY created_at DESC
LIMIT 1
结果:
id | game_id | mini_game_id | result | created_at
--------------------------------------------------
68 | 104 | 22 | 17 | 27/11/2016
问题:
显然,我只得到 1 个结果。但是我的想法是 limit 1
WHERE IN
中的每个值
你能帮我理解我是怎么做到的吗?
谢谢
WITH cte AS (
SELECT *
,DENSE_RANK() OVER (PARTITION by user_id ORDER BY created_at DESC) as LatestGame
,LAG(result) OVER (PARTITION BY user_id, mini_game_id ORDER BY created_at) as SecondToLastResult
FROM
Table
)
SELECT
id
,game_id
,mini_game_id
,result
,SecondToLastResult
,created_at as Date
FROM
cte
WHERE
LatestGame = 1
;
使用 DENSE_RANK()
定义最新游戏,使用 LAG()
获取之前的结果,然后 select 其中 LatestGame
= 1 来自常见的 table 表达式 [ cte]
这是 postgresql 的 link 关于 window 函数:https://www.postgresql.org/docs/8.4/static/functions-window.html
要仅筛选 1 个用户,您可以执行以下操作,因为您将不再需要按 user_id 划分 window 函数:
WITH cte AS (
SELECT *
,DENSE_RANK() OVER (ORDER BY created_at DESC) as LatestGame
,LAG(result) OVER (PARTITION BY mini_game_id ORDER BY created_at) as SecondToLastResult
FROM
Table
WHERE
user_id = 44
)
这里只是为了好玩,您可以如何使用 window 函数来做到这一点:
SELECT
t.id
,t.user_id
,t.game_id
,t.mini_game_id
,t.result
,t.created_at
,(SELECT result
FROM
Table t2
WHERE
t.user_id = t2.user_id
AND t.mini_game_id = t2.mini_game_id
AND t.created_at > t2.created_at
ORDER BY
t2.created_at DESC
LIMIT 1) as SecondToLastResult
FROM
Table t
LEFT JOIN Table t1
ON t.user_id = t1.user_id
AND t.created_at < t1.created_at
WHERE
t1.id IS NULL
AND t.user_id = 44
不过我认为 window 函数对您来说会更好。
我正在使用 PostgreSQL 数据库。
这里的想法:
- 一个用户可以玩一个游戏
- 每个游戏可以有1个或多个小游戏
- 每个小游戏都有一个结果
这里是数据库的种类:
id | user_id | game_id | mini_game_id | result | created_at
-----------------------------------------------------------
70 | 44 | 105 | 22 | 19 | 28/11/2016
69 | 44 | 105 | 20 | 18 | 28/11/2016
68 | 44 | 104 | 22 | 17 | 27/11/2016
67 | 44 | 104 | 21 | 16 | 27/11/2016
66 | 44 | 103 | 22 | 15 | 26/11/2016
65 | 44 | 103 | 21 | 14 | 26/11/2016
64 | 44 | 103 | 20 | 13 | 26/11/2016
我想在其最新游戏结束时显示每个 mini_game 的结果,以及前一个相同 mini_game 的结果。
需要的结果:
示例:对于 user 44
,在其 game 105
的末尾,我想获取此数据:
id | game_id | mini_game_id | second-to-last-result | date
-----------------------------------------------------------------
68 | 104 | 22 | 17 | 27/11/2016
64 | 103 | 20 | 13 | 26/11/2016
我尝试过的:
第一次尝试:
SELECT mini_game_id,
array_agg(result) as results,
array_agg(created_at) as dates
FROM result
WHERE user_id = 44
AND game_id != 105 --Exclude latest game
GROUP BY mini_game_id
ORDER BY mini_game_id
结果:
mini_game_id | results | dates
--------------------------------------------------
22 | {17, 15} | {27/11/2016, 26/11/2016}
21 | {16, 14} | {27/11/2016, 26/11/2016}
20 | {13} | {26/11/2016}
这里的问题是我为一个用户获取每个游戏的每个 mini_game 结果,这对我来说似乎太过分了,因为我可以有数千个结果...
第二次尝试:
SELECT id,
game_id,
mini_game_id,
result,
created_at
FROM result
WHERE user_id = 44
AND game_id != 105 --Exclude latest game
AND mini_game IN (22, 20) --The two mini-games the user have played in game 105
ORDER BY created_at DESC
LIMIT 1
结果:
id | game_id | mini_game_id | result | created_at
--------------------------------------------------
68 | 104 | 22 | 17 | 27/11/2016
问题:
显然,我只得到 1 个结果。但是我的想法是 limit 1
WHERE IN
你能帮我理解我是怎么做到的吗?
谢谢
WITH cte AS (
SELECT *
,DENSE_RANK() OVER (PARTITION by user_id ORDER BY created_at DESC) as LatestGame
,LAG(result) OVER (PARTITION BY user_id, mini_game_id ORDER BY created_at) as SecondToLastResult
FROM
Table
)
SELECT
id
,game_id
,mini_game_id
,result
,SecondToLastResult
,created_at as Date
FROM
cte
WHERE
LatestGame = 1
;
使用 DENSE_RANK()
定义最新游戏,使用 LAG()
获取之前的结果,然后 select 其中 LatestGame
= 1 来自常见的 table 表达式 [ cte]
这是 postgresql 的 link 关于 window 函数:https://www.postgresql.org/docs/8.4/static/functions-window.html
要仅筛选 1 个用户,您可以执行以下操作,因为您将不再需要按 user_id 划分 window 函数:
WITH cte AS (
SELECT *
,DENSE_RANK() OVER (ORDER BY created_at DESC) as LatestGame
,LAG(result) OVER (PARTITION BY mini_game_id ORDER BY created_at) as SecondToLastResult
FROM
Table
WHERE
user_id = 44
)
这里只是为了好玩,您可以如何使用 window 函数来做到这一点:
SELECT
t.id
,t.user_id
,t.game_id
,t.mini_game_id
,t.result
,t.created_at
,(SELECT result
FROM
Table t2
WHERE
t.user_id = t2.user_id
AND t.mini_game_id = t2.mini_game_id
AND t.created_at > t2.created_at
ORDER BY
t2.created_at DESC
LIMIT 1) as SecondToLastResult
FROM
Table t
LEFT JOIN Table t1
ON t.user_id = t1.user_id
AND t.created_at < t1.created_at
WHERE
t1.id IS NULL
AND t.user_id = 44
不过我认为 window 函数对您来说会更好。