Ben*_*ith 5 sql postgresql group-by left-join greatest-n-per-group
我正在使用 PostgreSQL 9.4。
我有一张桌子workouts。results用户可以为每个创建多个workout,并且一个result有一个score.
给定一个锻炼 ID 列表和两个用户 ID,我想返回每个用户每次锻炼的最佳分数。如果用户没有该锻炼的结果,我想返回填充/空结果。
SELECT "results".*, "workouts".*
FROM "results" LEFT JOIN "workouts" ON "workouts"."id" = "results"."workout_id"
WHERE (
(user_id, workout_id, score) IN
(SELECT user_id, workout_id, MAX(score)
FROM results WHERE user_id IN (1, 2) AND workout_id IN (1, 2, 3)
GROUP BY user_id, workout_id)
)
Run Code Online (Sandbox Code Playgroud)
在此查询中,左连接充当内连接;如果用户没有得到锻炼结果,我不会得到任何填充。无论存在多少结果,此查询都应始终返回六行。
示例数据:
results
user_id | workout_id | score
-----------------------------
1 | 1 | 10
1 | 3 | 10
1 | 3 | 15
2 | 1 | 5
Desired result:
results.user_id | results.workout_id | max(results.score) | workouts.name
-------------------------------------------------------------------------
1 | 1 | 10 | Squat
1 | 2 | null | Bench
1 | 3 | 15 | Deadlift
2 | 1 | 5 | Squat
2 | 2 | null | Bench
2 | 3 | null | Deadlift
Run Code Online (Sandbox Code Playgroud)
distinct on使用or怎么样row_number()?
SELECT DISTINCT ON (r.user_id, r.workout_id) r.*, w.*
FROM "results" r LEFT JOIN
"workouts" w
ON "w."id" = r."workout_id"
WHERE r.user_id IN (1, 2) AND r.workout_id IN (1, 2, 3)
ORDER BY r.user_id, r.workout_id, score desc;
Run Code Online (Sandbox Code Playgroud)
等效row_number()的需要一个子查询:
SELECT rw.*
FROM (SELECT r.*, w.*,
row_number() over (partition by user_id, workout_id order by score desc) as seqnum
FROM "results" r LEFT JOIN
"workouts" w
ON "w."id" = r."workout_id"
WHERE r.user_id IN (1, 2) AND r.workout_id IN (1, 2, 3)
) rw
WHERE seqnum = 1;
Run Code Online (Sandbox Code Playgroud)
您应该比使用 更明智地选择列*。如果列名重复,子查询可能会返回错误。
编辑:
您需要首先生成行,然后生成每行的结果。这是一种基于第二个查询的方法:
SELECT u.user_id, w.workout_id, rw.score, rw.name
FROM (SELECT 1 as user_id UNION ALL SELECT 2) u CROSS JOIN
(SELECT 1 as workout_id UNION ALL SELECT 2 UNION ALL SELECT 3) w LEFT JOIN
(SELECT r.*, w.*,
row_number() over (partition by user_id, workout_id order by score desc) as seqnum
FROM "results" r LEFT JOIN
"workouts" w
ON "w."id" = r."workout_id"
WHERE r.user_id IN (1, 2) AND r.workout_id IN (1, 2, 3)
) rw
ON rw.user_id = u.user_id and rw.workout_id = w.workout_id and
rw.seqnum = 1;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14871 次 |
| 最近记录: |