Select 基于组顺序的新列
Select new columns based on group order
我在这个网站上遇到了很多问题,但找不到解决方案。
我有一个 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
频道仅限于“A”、“B”、“C”、“D”、“E”、“F”。里面有很多行,不同的GROUPID。
我需要得到这个 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
当Channel在按Time排序的ID相同的行组中排在第一位时;否则为假。
IsLast = TRUE
当Channel是按时间排序的具有相同GroupID的行组中的最后一个时;否则为假。
Channelsingroup
- 同一组中的行数(具有相同的 GroupID)
Daysbeforelast
- 组中最新行与当前行之间的天数差异。
我无权创建或更新 table,只能创建或更新 select。
我希望以上数据有意义,有任何问题请告诉我。
您可以使用 ROW_NUMBER
获取 isFirst
和 isLast
列,使用 COUNT(*) OVER()
获取 ChannelsInGroup
。此外,您可以使用 CROSS APPLY
来计算 DaysBeforeLast
:
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)
结果
| 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 |
一种解决方案可能是使用窗口聚合函数:
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
试试这个。
select DATE_1 ,GroupID,CHANNEL
, case (select top 1 test.CHANNEL
from test
where test.GroupID = outer1.GroupID
order by test.CHANNEL) when outer1.CHANNEL then 'true' else 'false' end as isFirst
, case (select top 1 test.CHANNEL
from test
where test.GroupID = outer1.GroupID
order by test.CHANNEL desc) when CHANNEL then 'true' else 'false' end as isLast
, (select count(*)
from test
where test.GroupID = outer1.GroupID) Channelsingroup
, (select DATEDIFF(DAY,outer1.DATE_1,MAX(test.DATE_1))
from test
where test.GroupID = outer1.GroupID)
from test outer1
with cte
as
(select Date,GroupID ,Channel,row_number() over (partition by groupid order
by groupid) as first
from table1)
select Date,GroupID, Channel, case when first=1 then 'true' else 'false' end as
isFirst,
case when isfirst=b.Channelsingroup then 'true' else 'false' end as isLast
b.Channelsingroup, datediff(dd,getdate(),Daysbeforelast) as Daysbeforelast
from cte a
inner join (select count(*) as Channelsingroup ,max(date) as Daysbeforelast
from table1 group by groupid) as b
on a.groupid=b,groupid
我在这个网站上遇到了很多问题,但找不到解决方案。 我有一个 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
频道仅限于“A”、“B”、“C”、“D”、“E”、“F”。里面有很多行,不同的GROUPID。
我需要得到这个 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
当Channel在按Time排序的ID相同的行组中排在第一位时;否则为假。
IsLast = TRUE
当Channel是按时间排序的具有相同GroupID的行组中的最后一个时;否则为假。
Channelsingroup
- 同一组中的行数(具有相同的 GroupID)
Daysbeforelast
- 组中最新行与当前行之间的天数差异。
我无权创建或更新 table,只能创建或更新 select。
我希望以上数据有意义,有任何问题请告诉我。
您可以使用 ROW_NUMBER
获取 isFirst
和 isLast
列,使用 COUNT(*) OVER()
获取 ChannelsInGroup
。此外,您可以使用 CROSS APPLY
来计算 DaysBeforeLast
:
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)
结果
| 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 |
一种解决方案可能是使用窗口聚合函数:
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
试试这个。
select DATE_1 ,GroupID,CHANNEL
, case (select top 1 test.CHANNEL
from test
where test.GroupID = outer1.GroupID
order by test.CHANNEL) when outer1.CHANNEL then 'true' else 'false' end as isFirst
, case (select top 1 test.CHANNEL
from test
where test.GroupID = outer1.GroupID
order by test.CHANNEL desc) when CHANNEL then 'true' else 'false' end as isLast
, (select count(*)
from test
where test.GroupID = outer1.GroupID) Channelsingroup
, (select DATEDIFF(DAY,outer1.DATE_1,MAX(test.DATE_1))
from test
where test.GroupID = outer1.GroupID)
from test outer1
with cte
as
(select Date,GroupID ,Channel,row_number() over (partition by groupid order
by groupid) as first
from table1)
select Date,GroupID, Channel, case when first=1 then 'true' else 'false' end as
isFirst,
case when isfirst=b.Channelsingroup then 'true' else 'false' end as isLast
b.Channelsingroup, datediff(dd,getdate(),Daysbeforelast) as Daysbeforelast
from cte a
inner join (select count(*) as Channelsingroup ,max(date) as Daysbeforelast
from table1 group by groupid) as b
on a.groupid=b,groupid