I am trying to find an appropriate solution to the following problem: I have an activity-tracking database and I want to get the status at a specific date (ex: 11-Sept)
Activity | Status | Date |
---|---|---|
100 | Done | 12-Sept |
100 | In prog | 10-Sept |
110 | In prog | 12-Sept |
110 | In prog | 09-Sept |
110 | New | 08-Sept |
My current query is: select * from table where Date <= 11-Sept My current output is:
Activity | Status | Date |
---|---|---|
100 | In prog | 10-Sept |
110 | In prog | 09-Sept |
110 | New | 08-Sept |
Problem is I want to limit to only 1 row (newest date) for each activity code. Desired output is:
Activity | Status | Date |
---|---|---|
100 | In prog | 10-Sept |
110 | In prog | 09-Sept |
BUT...
I can't user group by, having or distinct, so the following solutions are not acceptable:
select distinct Name
from table
where Date <= 11-Sept
select name, max(date)
from table
where Date <= 11-Sept
group by name
Basically.. I can only use the where clause
Anyone has an idea?
Desired output is:
Activity | Status | Date |
---|---|---|
100 | In prog | 10-Sept |
110 | In prog | 09-Sept |
To be mentioned: the format of the date here is simplified
One canonical way to do this uses the ROW_NUMBER()
window function:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Activity ORDER BY Date DESC) rn
FROM yourTable
WHERE Date < '20230911'
)
SELECT Activity, Status, Date
FROM cte
WHERE rn = 1
ORDER BY Activity;
Another more concise (yet less performant) way:
SELECT TOP 1 WITH TIES Activity, Status, Date
FROM yourTable
WHERE Date <= '20230911'
ORDER BY ROW_NUMBER() OVER (PARTITION BY Activity ORDER BY Date DESC);
A third option, using exists logic:
SELECT Activity, Status, Date
FROM yourTable t1
WHERE
Date <= '20230911' AND
NOT EXISTS (
SELECT 1
FROM yourTable t2
WHERE t2.Date <= '20230911' AND
t2.Activity = t1.Activity AND
t2.Date > t1.Date
)
ORDER BY Activity;