Reputation: 21
Given this data:
ID FirstDate LastDate ItemId
12A 05-11-2011 05-11-2011 0
12A 12-19-2011 12-19-2011 3
12A 01-04-2012 01-04-2012 3
12A 01-19-2012 01-19-2012 12
64B 06-15-2010 06-15-2010 0
64B 08-19-2011 08-19-2011 3
I want to see:
ID FirstDate FirstItemId LastDate LastItemId
12A 05-11-2011 0 01-19-2012 12
64B 06-15-2010 0 08-19-2011 3
Upvotes: 0
Views: 2050
Reputation: 15251
In it's most basic form, you will probably want to combine the SQL min
and group by
functionality:
select ID
, min(FirstDate) as FirstDate
, min(ItemId) as FirstItemId
, max(LastDate) as LastDate
, max(ItemId) as LastItemId
from MyTable
group by ID
Note, however, that this will return the absolute min and max values for each column, not necessarily the ItemId that corresponds to the FirstDate and such, unless the data happens to be that way. Here is one possible alternative to that to get ItemIDs based upon the first/last dates:
-- Get ItemIDs that correspond to First/Last Dates
select ID
, FirstDate
, (select min(ItemID) from Mytable where ID = a.ID and FirstDate = a.FirstDate) as FirstItemID
, LastDate
, (select max(ItemID) from Mytable where ID = a.ID and LastDate = a.LastDate) as LastItemID
from (
select ID
, min(FirstDate) as FirstDate
, max(LastDate) as LastDate
from Mytable
group by ID
) as a
I find that correlated subqueries can often be faster than windowing functions (and possibly easier to understand), but you must test in your environment with your data.
Upvotes: 0
Reputation: 247690
You can use a combination of windowing functions to get this result:
select id,
max(case when FirstRowNumber= 1 then firstdate end) firstdate,
max(case when FirstRowNumber= 1 then itemid end) firstitemId,
max(case when LastRowNumber= 1 then lastdate end) lastdate,
max(case when LastRowNumber= 1 then itemid end) lastitemId
from
(
select id, firstdate, lastdate, itemid,
row_number() over(partition by id order by firstdate) FirstRowNumber,
row_number() over(partition by id order by lastdate desc) LastRowNumber
from yourtable
) x
where FirstRowNumber= 1
or LastRowNumber= 1
group by id
See SQL Fiddle with Demo.
This solution assigns the row_number
to the records in both ASC/DESC date order. Then you only care about the records where the row_number = 1
. I then applied an aggregate and a CASE
statement to the values to get the correct result.
Or you can use a very ugly UNPIVOT
and PIVOT
solution:
select *
from
(
select id,
val,
case when firstrownumber = 1 and col = 'firstdate'
then 'firstdate'
when firstrownumber = 1 and col = 'itemid'
then 'firstitemid'
when LastRowNumber = 1 and col = 'lastdate'
then 'lastdate'
when LastRowNumber = 1 and col = 'itemid'
then 'lastitemid'
else '' end col
from
(
select id,
convert(varchar(10), firstdate, 120) firstdate,
convert(varchar(10), lastdate, 120) lastdate,
cast(itemid as varchar(10)) itemid,
row_number() over(partition by id order by firstdate) FirstRowNumber,
row_number() over(partition by id order by lastdate desc) LastRowNumber
from yourtable
) x
unpivot
(
val for col in (firstdate, lastdate, itemid)
) u
) x1
pivot
(
max(val)
for col in ([firstdate], [firstitemid],
[lastdate], [lastitemid])
) p
Upvotes: 1