Reputation: 137
With my data I have individuals taking an assessment multiple times at different dates. It looks something like this:
╔════════╦═══════════╦═══════════╦═══════╗
║ Person ║ ID Number ║ Date ║ Score ║
║ John ║ 134 ║ 7/11/2013 ║ 18 ║
║ John ║ 134 ║ 8/23/2013 ║ 16 ║
║ John ║ 134 ║ 9/30/2013 ║ 16 ║
║ Kate ║ 887 ║ 2/28/2013 ║ 21 ║
║ Kate ║ 887 ║ 3/16/2013 ║ 19 ║
║ Bill ║ 990 ║ 4/18/2013 ║ 15 ║
║ Ken ║ 265 ║ 2/12/2013 ║ 23 ║
║ Ken ║ 265 ║ 4/25/2013 ║ 20 ║
║ Ken ║ 265 ║ 6/20/2013 ║ 19 ║
║ Ken ║ 265 ║ 7/15/2013 ║ 19 ║
╚════════╩═══════════╩═══════════╩═══════╝
I'd like it to have another column at the end that calculates the number of days since the first assessment for that person. I'd also settle for the number of days since the previous assessment for that person if that's easier.
Ideally it would look like this:
╔════════╦═══════════╦═══════════╦═══════╦══════════════════╗
║ Person ║ ID Number ║ Date ║ Score ║ Days Since First ║
║ John ║ 134 ║ 7/11/2013 ║ 18 ║ 0 ║
║ John ║ 134 ║ 8/23/2013 ║ 16 ║ 43 ║
║ John ║ 134 ║ 9/30/2013 ║ 16 ║ 81 ║
║ Kate ║ 887 ║ 2/28/2013 ║ 21 ║ 0 ║
║ Kate ║ 887 ║ 3/16/2013 ║ 19 ║ 16 ║
║ Bill ║ 990 ║ 4/18/2013 ║ 15 ║ 0 ║
║ Ken ║ 265 ║ 2/12/2013 ║ 23 ║ 0 ║
║ Ken ║ 265 ║ 4/25/2013 ║ 20 ║ 72 ║
║ Ken ║ 265 ║ 6/20/2013 ║ 19 ║ 128 ║
║ Ken ║ 265 ║ 7/15/2013 ║ 19 ║ 153 ║
╚════════╩═══════════╩═══════════╩═══════╩══════════════════╝
Upvotes: 4
Views: 7844
Reputation: 16904
You can use option with APPLY operator
1.difference between the current row date and the previous date
SELECT t1.*,
DATEDIFF(dd, ISNULL(o.[Date], t1.[Date]), t1.[Date]) AS [Days Since First]
FROM YourTable t1 OUTER APPLY (
SELECT TOP 1 [Date]
FROM YourTable t2
WHERE t1.[ID Number] = t2.[ID Number]
AND t1.[Date] > t2.[Date]
ORDER BY t2.[Date] DESC
) o
See example on SQLFiddle
2.number of days since the first assessment
SELECT t1.*,
DATEDIFF(dd, ISNULL(o.[Date], t1.[Date]), t1.[Date]) AS [Days Since First]
FROM YourTable t1 OUTER APPLY (
SELECT MIN(t2.[Date]) AS [Date]
FROM YourTable t2
WHERE t1.[ID Number] = t2.[ID Number]
) o
See example on SQLFiddle
Upvotes: 1
Reputation: 34784
I like Andomar's answer, but if you wanted to find both days between and total days since first you could do this:
SELECT a.*
,ISNULL(DATEDIFF(day,b.Date,a.Date),0)'Since Previous'
,datediff(day, min(a.Date) over (partition by a.[ID Number]), a.Date)'Since First'
FROM (select *,ROW_NUMBER() OVER(PARTITION BY [ID Number] ORDER BY DATE)RowRank
from YourTable
)a
LEFT JOIN (select *,ROW_NUMBER() OVER(PARTITION BY [ID Number] ORDER BY DATE)RowRank
from YourTable
)b
ON a.[ID Number] = b.[ID Number]
AND a.RowRank = b.RowRank + 1
Demo: SQL Fiddle
Upvotes: 4
Reputation: 238296
select *
, datediff(day, min(Date) over (partition by [ID Number]), Date)
from YourTable
Upvotes: 6