在不连续的时间段 YYYYMM00 上查找 MIN 和 MAX 日期
Find MIN and MAX date on a discontinuous period of time YYYYMM00
我有以下两个table:
- DimensionTime 是一个包含每个月的 table,按 ID 排序,格式为 YYYMM00
- LogPlayer 是一个 table,其中有一些与玩家和特定月份相关的统计数据。
我想得到的是:
+--------+--------+----------+----------+
| Player | Team | Start | End |
+--------+--------+----------+----------+
| John | Red | 20180100 | 20180300 |
| John | Red | 20180600 | 20180700 |
| Luke | Yellow | 20180100 | 20180100 |
| Luke | Yellow | 20190100 | 20190100 |
+--------+--------+----------+----------+
我无法使用 MIN 和 MAX 函数,因为句点不连续...我该如何解决?
我尝试将 MIN/MAX 与 GROUP BY 结合使用,但没有得到任何有用的信息。我在 Whosebug 上找不到任何问题或答案。
SELECT *
INTO #DimensionTime
FROM (
SELECT 1 AS [ID], 20180100 AS [TIMEID]
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID]
UNION ALL
SELECT 3 AS [ID], 20180300 AS [TIMEID]
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID]
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID]
UNION ALL
SELECT 6 AS [ID], 20180600 AS [TIMEID]
UNION ALL
SELECT 7 AS [ID], 20180700 AS [TIMEID]
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID]
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID]
UNION ALL
SELECT 10 AS [ID], 20181000 AS [TIMEID]
UNION ALL
SELECT 11 AS [ID], 20181100 AS [TIMEID]
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID]
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID]
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID]
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID]
) A
SELECT *
INTO #LogPlayer
FROM (
SELECT 'John' AS [Player], 'Red' AS [Team], 20180100 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180200 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180300 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180600 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180700 AS [TIMEID]
UNION ALL
SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20180100 AS [TIMEID]
UNION ALL
SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20190100 AS [TIMEID]
) B
您可以执行此类操作来查找 运行 个日期的开始和结束。
通过 CTE 转换为 'date'(我认为它存在于 2005 年)
然后使用 Cross Apply an EXIST 来查找 运行 of dates
的开始和结束
你没有提供球员和球队的数据,但你可以在 EXISTS 中添加 WHERE 条件,然后 GROUP BY - 如果需要的话
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT from #DimensionTime)
select CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.DT)
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where d2.DT = dateadd(month,-1,d1.DT)) ;
猜测一些样本数据,我尝试了
SELECT *
INTO #DimensionTime
FROM (
SELECT 1 AS [ID], 20180100 AS [TIMEID], 'john' as player, 'red' as team
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 3 AS [ID], 20180300 AS [TIMEID], 'john','red'
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID], 'john','red'
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID], 'john','red'
UNION ALL
SELECT 7 AS [ID], 20180700 AS [TIMEID], 'john','red'
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID], 'john','red'
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID], 'john','red'
UNION ALL
SELECT 11 AS [ID], 20181100 AS [TIMEID], 'john','red'
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID], 'john','red'
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID], 'john','red'
UNION ALL
SELECT 1 AS [ID], 20180100 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID], 'luke','yellow'
) A
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #DimensionTime)
select d1.team,d1.player,
CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
d3.player = d1.player
and
d3.team = d1.team
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
and d4.team = d3.team
and d4.player = d3.player
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where
d2.player=d1.player
and
d2.team = d1.team
and
d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;
drop table #DimensionTime;
抱歉我错过了最新的表格,我设计了
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #LogPlayer)
select d1.team,d1.player,
CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
d3.player = d1.player
and
d3.team = d1.team
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
and d4.team = d3.team
and d4.player = d3.player
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where
d2.player=d1.player
and
d2.team = d1.team
and
d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;
这是一种间隙和孤岛问题。即使在 SQL Server 2005 等不受支持的古老软件中也可以解决,因为该版本具有 row_number()
.
一个技巧是将时间 ID 转换为 真正的 date/time。另一个技巧是通过从 date/time 值中减去连续的月数来定义组:
select player, team, min(timeid), max(timeid)
from (select lp.*,
row_number() over (partition by player, team order by timeid) as seqnum,
cast(cast(timeid + 1 as varchar(255)) as datetime) as yyyymm
from logplayer lp
) lp
group by player, team, dateadd(month, - seqnum, yyyymm)
order by player, team, min(timeid);
Here 是一个 db<>fiddle.
我有以下两个table:
- DimensionTime 是一个包含每个月的 table,按 ID 排序,格式为 YYYMM00
- LogPlayer 是一个 table,其中有一些与玩家和特定月份相关的统计数据。
我想得到的是:
+--------+--------+----------+----------+
| Player | Team | Start | End |
+--------+--------+----------+----------+
| John | Red | 20180100 | 20180300 |
| John | Red | 20180600 | 20180700 |
| Luke | Yellow | 20180100 | 20180100 |
| Luke | Yellow | 20190100 | 20190100 |
+--------+--------+----------+----------+
我无法使用 MIN 和 MAX 函数,因为句点不连续...我该如何解决? 我尝试将 MIN/MAX 与 GROUP BY 结合使用,但没有得到任何有用的信息。我在 Whosebug 上找不到任何问题或答案。
SELECT *
INTO #DimensionTime
FROM (
SELECT 1 AS [ID], 20180100 AS [TIMEID]
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID]
UNION ALL
SELECT 3 AS [ID], 20180300 AS [TIMEID]
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID]
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID]
UNION ALL
SELECT 6 AS [ID], 20180600 AS [TIMEID]
UNION ALL
SELECT 7 AS [ID], 20180700 AS [TIMEID]
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID]
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID]
UNION ALL
SELECT 10 AS [ID], 20181000 AS [TIMEID]
UNION ALL
SELECT 11 AS [ID], 20181100 AS [TIMEID]
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID]
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID]
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID]
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID]
) A
SELECT *
INTO #LogPlayer
FROM (
SELECT 'John' AS [Player], 'Red' AS [Team], 20180100 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180200 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180300 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180600 AS [TIMEID]
UNION ALL
SELECT 'John' AS [Player], 'Red' AS [Team], 20180700 AS [TIMEID]
UNION ALL
SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20180100 AS [TIMEID]
UNION ALL
SELECT 'Luke' AS [Player], 'Yellow' AS [Team], 20190100 AS [TIMEID]
) B
您可以执行此类操作来查找 运行 个日期的开始和结束。
通过 CTE 转换为 'date'(我认为它存在于 2005 年) 然后使用 Cross Apply an EXIST 来查找 运行 of dates
的开始和结束你没有提供球员和球队的数据,但你可以在 EXISTS 中添加 WHERE 条件,然后 GROUP BY - 如果需要的话
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT from #DimensionTime)
select CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.DT)
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where d2.DT = dateadd(month,-1,d1.DT)) ;
猜测一些样本数据,我尝试了
SELECT *
INTO #DimensionTime
FROM (
SELECT 1 AS [ID], 20180100 AS [TIMEID], 'john' as player, 'red' as team
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 3 AS [ID], 20180300 AS [TIMEID], 'john','red'
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID], 'john','red'
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID], 'john','red'
UNION ALL
SELECT 7 AS [ID], 20180700 AS [TIMEID], 'john','red'
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID], 'john','red'
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID], 'john','red'
UNION ALL
SELECT 11 AS [ID], 20181100 AS [TIMEID], 'john','red'
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID], 'john','red'
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID], 'john','red'
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID], 'john','red'
UNION ALL
SELECT 1 AS [ID], 20180100 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 2 AS [ID], 20180200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 4 AS [ID], 20180400 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 5 AS [ID], 20180500 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 8 AS [ID], 20180800 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 9 AS [ID], 20180900 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 12 AS [ID], 20181200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 13 AS [ID], 20190100 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 14 AS [ID], 20190200 AS [TIMEID], 'luke','yellow'
UNION ALL
SELECT 15 AS [ID], 20190300 AS [TIMEID], 'luke','yellow'
) A
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #DimensionTime)
select d1.team,d1.player,
CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
d3.player = d1.player
and
d3.team = d1.team
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
and d4.team = d3.team
and d4.player = d3.player
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where
d2.player=d1.player
and
d2.team = d1.team
and
d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;
drop table #DimensionTime;
抱歉我错过了最新的表格,我设计了
;WITH dats as (SELECT CAST(LEFT(timeid, 6) + '01' as datetime) as DT,player,team from #LogPlayer)
select d1.team,d1.player,
CONVERT(varchar(7),d1.DT,112) +'0' as strt,
CONVERT(varchar(7),dq.dt,112) +'0' as [end] from dats d1
CROSS APPLY
(SELECT TOP 1 d3.dt from dats d3 where
d3.dt > d1.dt
and
d3.player = d1.player
and
d3.team = d1.team
and
not exists(
select 0 from dats d4 where d4.DT = dateadd(month,1,d3.Dt)
and d4.team = d3.team
and d4.player = d3.player
)
ORDER BY d3.dt asc) DQ
where not exists(select 0 from dats d2 where
d2.player=d1.player
and
d2.team = d1.team
and
d2.DT = dateadd(month,-1,d1.DT) and d1.team=d2.team and d1.player = d2.player ) ;
这是一种间隙和孤岛问题。即使在 SQL Server 2005 等不受支持的古老软件中也可以解决,因为该版本具有 row_number()
.
一个技巧是将时间 ID 转换为 真正的 date/time。另一个技巧是通过从 date/time 值中减去连续的月数来定义组:
select player, team, min(timeid), max(timeid)
from (select lp.*,
row_number() over (partition by player, team order by timeid) as seqnum,
cast(cast(timeid + 1 as varchar(255)) as datetime) as yyyymm
from logplayer lp
) lp
group by player, team, dateadd(month, - seqnum, yyyymm)
order by player, team, min(timeid);
Here 是一个 db<>fiddle.