我有3个表user
,session
和log
。用户表存储所有用户相关信息,而会话只是将用户与日志连接。我想获得具有最新日志条目的所有用户的列表。表格设计如下:
user (id, name, ...)
session (id, user_id)
log (id, session_id, time, type, ...)
我当前的查询看起来像这样
SELECT *
FROM USER AS u
INNER JOIN session AS s
ON u.id = s.user_id
INNER JOIN log AS l
ON l.session_id = s.id
ORDER BY l.time DESC
但不难想象这只会返回按日期排序的所有3个表的数据。我如何获得一个结果,我只是让每个用户只使用log(desc)时间排序的最新日志条目中的数据?
提前感谢您的帮助。
答案 0 :(得分:2)
您可以将DISTINCT ON与ORDER BY
结合使用,按日期获取每位用户的最新行数。这将允许您选择所需的其他字段:
SELECT DISTINCT ON (u.id)
u.id,
u.Name,
l.type,
l.time
FROM user AS u
INNER JOIN session AS s ON u.id = s.user_id
INNER JOIN log AS l ON l.session_id = s.id
ORDER BY u.id, l.time DESC;
N.B。我不确切知道您需要哪些列,但我添加了一些用来演示,因为我不想提倡使用SELECT *
为了完整性,还有其他几种方法可以实现这一点,第一种是在子查询中选择max并在user_id和time上连接回外部查询:
SELECT u.id,
u.Name,
l.type,
l.time
FROM user AS u
INNER JOIN session AS s
ON u.id = s.user_id
INNER JOIN log AS l
ON l.session_id = s.id
INNER JOIN
( SELECT s.user_id, MAX(l.time) AS time
FROM session AS s
INNER JOIN log AS l
ON l.session_id = s.id
GROUP BY s.user_id
) AS MaxLog
ON MaxLog.user_id = u.id
AND MaxLog.time = l.time
ORDER BY l.time DESC;
或者您可以使用ROW_NUMBER()
:
SELECT id, Name, type, time
FROM ( SELECT u.id,
u.Name,
l.type,
l.time,
ROW_NUMBER() OVER(PARTITION BY u.id ORDER BY l.time DESC) AS RowNumber
FROM user AS u
INNER JOIN session AS s
ON u.id = s.user_id
INNER JOIN log AS l
ON l.session_id = s.id
) u
WHERE RowNumber = 1;
答案 1 :(得分:1)
我假设了一些架构(user.user_name
?),但您可以通过分组和Max
之类的聚合来实现这一点:
SELECT u.user_id,
u.user_name,
Max(l.time) AS LastLogTime
FROM USER AS u
LEFT JOIN session AS s
ON u.id = s.user_id
INNER JOIN log AS l
ON l.session_id = s.id
GROUP BY u.user_id,
u.user_name;
由于我们需要使用select *
,您将无法GROUP BY
同样,ORDER BY l.time
不再适用 - 您仍然可以通过以下方式订购user_name
我也LEFT JOINED
- 这样,如果用户没有会话,它仍会返回用户的记录,可能是LastLogTime
为NULL。