I went through many questions on this site but wasn’t able to find solution. I’ve got a table:
Date GroupID CHANNEL 24/02/2015 1 A 26/02/2015 1 B 27/02/2015 1 C 21/03/2015 2 D 20/02/2015 3 E 25/02/2015 3 D 28/02/2015 4 C 04/03/2015 5 B 05/03/2015 5 E 10/03/2015 5 D 11/03/2015 5 A 14/03/2015 5 C 23/03/2015 5 F 28/03/2015 6 E
Channel are limited to ‘A’,’B’,’C’,’D’,’E’,’F’. There are quite a lot of rows in it with different GROUPIDs.
I need to get this table:
Date GroupID Channel isFirst isLast Channelsingroup Daysbeforelast 24/02/2015 1 A TRUE FALSE 3 3 26/02/2015 1 B FALSE FALSE 3 1 27/02/2015 1 C FALSE TRUE 3 0 21/03/2015 2 D TRUE TRUE 1 0 20/02/2015 3 E TRUE FALSE 2 5 25/02/2015 3 D FALSE FALSE 2 0 28/02/2015 4 C TRUE TRUE 1 0 04/03/2015 5 B TRUE FALSE 6 19 05/03/2015 5 E FALSE FALSE 6 18 10/03/2015 5 D FALSE FALSE 6 13 11/03/2015 5 A FALSE FALSE 6 12 14/03/2015 5 C FALSE FALSE 6 9 23/03/2015 5 F FALSE FALSE 6 0 28/03/2015 6 E TRUE TRUE 1 0
IsFirst = TRUE
when the Channel is the first in the group of rows with the same ID sorted by Time; otherwise FALSE.
IsLast = TRUE
when the Channel is the last in the group of rows with the same GroupID sorted by Time; otherwise FALSE.
Channelsingroup
- number of rows in the same group (with the same GroupID)
Daysbeforelast
- datediff in days between latest row in the group and the current one.
I have no access to create or update table, only to select.
I hope the above data make sense, any questions please let me know.
One solution could be to use windowed aggregate functions:
select
*,
case when date = MIN(date) over (partition by groupid order by groupid) then 'TRUE' else 'FALSE' end isFirst,
case when date = MAX(date) over (partition by groupid order by groupid) then 'TRUE' else 'FALSE' end isLast,
count(*) over (partition by groupid order by groupid) Channelsingroup,
datediff(day,date,MAX(date) over (partition by groupid order by groupid)) Daysbeforelast
from your_table
Sample SQL Fiddle
You can use ROW_NUMBER
to get the isFirst
and isLast
column and COUNT(*) OVER()
for the ChannelsInGroup
. Additionally, you can use CROSS APPLY
to compute for the DaysBeforeLast
:
SQL Fiddle
WITH Cte AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY GroupID ORDER BY [Date]),
CC = COUNT(*) OVER(PARTITION BY GroupID)
FROM TestData
)
SELECT
c.[Date],
c.GroupID,
c.Channel,
isFirst = CASE WHEN c.RN = 1 THEN 'TRUE' ELSE 'FALSE' END,
isLast = CASE WHEN c.RN = c.CC THEN 'TRUE' ELSE 'FALSE' END,
ChannelsInGroup = c.CC,
DaysBeforeLast = DATEDIFF(DAY, c.[Date], x.LastDate)
FROM Cte c
CROSS APPLY(
SELECT TOP 1 [Date]
FROM Cte
WHERE
RN = CC
AND GroupID = c.GroupID
ORDER BY [Date] DESC
)x(LastDate)
Result
| Date | GroupID | Channel | isFirst | isLast | ChannelsInGroup | DaysBeforeLast |
|------------|---------|---------|---------|--------|-----------------|----------------|
| 2015-02-24 | 1 | A | TRUE | FALSE | 3 | 3 |
| 2015-02-26 | 1 | B | FALSE | FALSE | 3 | 1 |
| 2015-02-27 | 1 | C | FALSE | TRUE | 3 | 0 |
| 2015-03-21 | 2 | D | TRUE | TRUE | 1 | 0 |
| 2015-02-20 | 3 | E | TRUE | FALSE | 2 | 5 |
| 2015-02-25 | 3 | D | FALSE | TRUE | 2 | 0 |
| 2015-02-28 | 4 | C | TRUE | TRUE | 1 | 0 |
| 2015-03-04 | 5 | B | TRUE | FALSE | 6 | 19 |
| 2015-03-05 | 5 | E | FALSE | FALSE | 6 | 18 |
| 2015-03-10 | 5 | D | FALSE | FALSE | 6 | 13 |
| 2015-03-11 | 5 | A | FALSE | FALSE | 6 | 12 |
| 2015-03-14 | 5 | C | FALSE | FALSE | 6 | 9 |
| 2015-03-23 | 5 | F | FALSE | TRUE | 6 | 0 |
| 2015-03-28 | 6 | E | TRUE | TRUE | 1 | 0 |
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With