Reputation: 713
Working on SQL Server 2008 and I've been struggling with how to query this. Suppose I have the following table:
ID Status Date (YYYY-MM-DD)
A-1 Open 2018-01-01
A-1 Closed 2018-01-05
B-2 Closed 2018-02-01
B-2 Open 2018-02-06
B-2 Closed 2018-02-06
C-3 Closed 2018-03-01
C-3 Open 2018-03-03
C-3 Closed 2018-03-05
C-3 Open 2018-03-07
I want the results to be a table consisting of the ID and the status and date corresponding to the most recent activity for that ID. In the event that there is both an Open and Closed status on the same date, it should default to Closed. So, using the table above, the results should be:
ID Status Date (YYYY-MM-DD)
A-1 Closed 2018-01-05
B-2 Closed 2018-02-06
C-3 Open 2018-03-07
Upvotes: 3
Views: 1022
Reputation: 81930
There is always the WITH TIES option.
The CTE method tends to be slightly more performant.
SELECT Top 1 with ties *
From YourTable
Order By Row_Number() over (Partition By ID Order By Date Desc)
Upvotes: 1
Reputation: 60462
WITH cte AS
(
SELECT *
,ROW_NUMBER()
OVER(PARTITION BY ID -- latest date per ID, prefer 'Closed' over 'Open'
ORDER BY Date DESC, Status) AS rn
FROM tab
)
SELECT * -- all columns but rn
FROM cte
WHERE rn = 1;
Upvotes: 3
Reputation: 1269445
In SQL Server, you can use row_number()
. Often the most efficient method, though, is the more old-fashioned:
select t.*
from t
where t.date = (select max(t2.date) from t t2 where t2.id = t.id);
This is particularly true if you have an index on t(id, date)
.
Another method that can have better performance is apply
. This assumes that you have a table of ids
:
select t.*
from ids cross apply
(select top 1 t.*
from t
where t.id = ids.id
order by t.date desc
) t;
Upvotes: 1
Reputation: 175556
You could use ROW_NUMBER
:
SELECT *
FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Date DESC) AS rn
FROM tab) sub
WHERE sub.rn = 1;
Upvotes: 1