SQL组合3个表,只获取具有最新日期的行

时间:2014-02-25 10:28:54

标签: sql postgresql

我有3个表usersessionlog。用户表存储所有用户相关信息,而会话只是将用户与日志连接。我想获得具有最新日志条目的所有用户的列表。表格设计如下:

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)时间排序的最新日志条目中的数据?

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您可以将DISTINCT ONORDER 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。