I have a history table that contains a score per group per date (PK is group, date). What is the SQL query that can retrieve the scores for all groups for the 2nd most recent date?
ETA: The dates are the same a开发者_Go百科cross groups (each score is entered into the history table at the same time for each group).
select *
from ScoreHistory sc1
where exists
(
select GroupId, max(ScoreDate) RecentScoreDate
from ScoreHistory sc2
where not exists
(
select GroupId, max(ScoreDate) RecentScoreDate
from ScoreHistory sc3
group by GroupId
having GroupId = sc2.GroupId and max(ScoreDate) = sc2.ScoreDate
)
group by GroupId
having GroupId = sc1.GroupId and max(ScoreDate) = sc1.ScoreDate
)
Setup:
create table ScoreHistory(GroupId int, ScoreDate datetime)
insert ScoreHistory
select 1, '2011-06-14' union all
select 1, '2011-06-15' union all
select 1, '2011-06-16' union all
select 2, '2011-06-15' union all
select 2, '2011-06-16' union all
select 2, '2011-06-17'
The query would looks as simple as below for MS SQL 2005 +
;with cte
as
(
select *, row_number() over(partition by GroupId order by ScoreDate desc) RowNumber
from ScoreHistory
)
select *
from cte
where RowNumber = 2
You need two aggregates
- get max dates per group
- get max dates per group that are less then the dates from step 1
- join back to the score from this aggregate
Something like
SELECT
Group, Date, Score
FROM
( ..2nd max date per group
SELECT
Group, MAX(Date) AS TakeMe
FROM
( --max date per group
SELECT
Group, MAX(Date) AS IgnoreMe
FROM
MyTable
GROUP BY
Group
) ex
JOIN
MyTable M ON ex.Group = M.Group AND ex.IgnoreMe > M.Date
GROUP BY
M.Group
) inc
JOIN
MyTable M2 ON inc.Group = M2.Group AND inc.TakeMe = M2.Date
This is so much easier on SQL Server 2005 with ROW_NUMBER()...
SELECT *
FROM tblScore
WHERE EXISTS
(
SELECT NULL
FROM tblScore as tblOuter
WHERE NOT EXISTS
(
SELECT NULL
FROM tblScore As tblInner
WHERE tblInner.[group] = tblOuter.[group]
GROUP BY [group]
HAVING MAX(tblInner.[date]) = tblOuter.[date]
)
AND tblOuter.[group] = tblScore.[group]
GROUP BY [group]
HAVING MAX(tblOuter.[date]) = tblScore.[date]
)
Try this. I am trying to get the TOP 2 DISTINCT
Dates Desc first which will work if you are using just dates and not datetimes. Then reversing that table and getting the TOP 1
and using that result as the 2nd most recent date to get the groups scores.
SELECT *
FROM YourTable
INNER JOIN
(SELECT TOP 1 x.[date]
FROM
(SELECT TOP 2 DISTINCT [date]
FROM YourTable
ORDER BY [date] DESC) AS x
ORDER BY [date] ASC) AS y
ON y.[date] = YourTable.[date]
I think this may need a WHERE y.date = YourTable.date
but I am not sure
精彩评论