从表中查找给定条件的最新记录

时间:2017-06-16 03:39:48

标签: sql sql-server-2012

这似乎是一个重复的问题,但我在SO上找到的所有答案都没有帮助我解决这个问题。

所以,我有这个数据库存储项目的每个更新。基本上,首次创建项目时,statusId为1,并且创建日期。如果有人更新了该项目并更改了该项目的状态,则会添加该项目的statusId。例如。使用当前日期添加statusId 2的新行。等等等等。该表的一个示例如下所示:

id  statusId    updatedDate             userId  authId
1   1           2016-12-20 15:43:17.703 14      14
2   1           2016-12-20 15:54:01.523 14      15
3   2           2016-12-21 16:05:48.157 14      14
4   3           2016-12-21 16:27:58.610 14      15
5   1           2016-12-20 17:16:47.627 14      18
6   1           2016-12-20 17:27:58.930 14      19
7   1           2017-01-18 14:13:35.800 18      20

所以,我接下来要做的是查询给出最新statusId的表格。对于上表,statusid = 1的查询应显示以下结果:

id  statusId    updatedDate             userId  authId
5   1           2016-12-20 17:16:47.627 14      18
6   1           2016-12-20 17:27:58.930 14      19
7   1           2017-01-18 14:13:35.800 18      20

注意该列表如何显示authIds 14和15,即使它具有状态1但在较晚的日期具有不同的statusId。

我尝试过的一种方法如下:

select A1.id, A1.statusId, A1.updatedDate, A1.userId, A1.authId from AuthProgressTracker A1
    left join AuthProgressTracker A2
    on (A1.authId = A2.authId and A1.updatedDate > A2.updatedDate)
    where A2.authId is not null 

没有显示我正在寻找的结果。我尝试了另一个

SELECT *
    FROM AuthProgressTracker T
    INNER JOIN (
            SELECT id, authId, statusId, MAX(updatedDate) as maxDate FROM AuthProgressTracker GROUP BY authId, statusId, id
        ) AP 
        ON AP.id = T.id AND T.updatedDate = AP.maxDate 
        order by T.id

这也没有产生预期的结果。

我错过了什么?

我如何分解SQL Server 2012中的问题,以便我能够在将来学会解决这样的问题?

2 个答案:

答案 0 :(得分:2)

您的问题陈述可能会让您误入歧途,因为虽然您想要最新的记录,但时间戳可能不是您到达结果集的方式。在下面的查询中,我使用了一个子查询,该子查询标识了authId以外的statusId的所有1。然后,它会过滤原始表格,为您提供所需的结果。

SELECT t1.*
FROM AuthProgressTracker t1
INNER JOIN
(
    SELECT authId
    FROM AuthProgressTracker
    GROUP BY authId
    HAVING SUM(CASE WHEN statusId <> 1 THEN 1 ELSE 0 END) = 0
) t2
    ON t1.authId = t2.authId

答案 1 :(得分:0)

(您尚未说明您正在使用的RDBMS,因此您需要相应地调整查询。例如,如果使用mysql,请使用LIMIT语法而不是TOP。)

declare @AuthProgressTracker table (
    id int,
    statusId int,
    updatedDate datetime,
    userId int,
    authId int
)
insert into @AuthProgressTracker
values 
(1,   1,           '2016-12-20 15:43:17.703', 14,      14),
(2,   1,           '2016-12-20 15:54:01.523', 14,      15),
(3,   2,           '2016-12-21 16:05:48.157', 14,      14),
(4,   3,           '2016-12-21 16:27:58.610', 14,      15),
(5,   1,           '2016-12-20 17:16:47.627', 14,      18),
(6,   1,           '2016-12-20 17:27:58.930', 14,      19),
(7,   1,           '2017-01-18 14:13:35.800', 18,      20)


/* Determine id's of latest status updates per authId */
SELECT  MAX(id) as LatestSatus
FROM    @AuthProgressTracker
GROUP BY authId

/* Note the above includes row id's you've chosen to exclude, so... */
/* Determine most recent statusId */
SELECT  TOP 1 statusId
FROM    @AuthProgressTracker
ORDER BY updatedDate DESC

/* Putting it all together */
SELECT  i.*
FROM    @AuthProgressTrackeri
        INNER JOIN (
        SELECT  MAX(id) as LatestSatus
        FROM    @AuthProgressTracker
        GROUP BY authId
        ) ls ON
            ls.LatestSatus = i.id
WHERE   i.statusId = (
        SELECT  TOP 1 statusId
        FROM    @AuthProgressTracker
        ORDER BY updatedDate DESC
        )