拆分跨天的时间数据

数据表记录了用户每次离开房间时的离开时间、游戏时长、在线时长,现在需统计用户每天的在线时长数据。现实中存在用户前一天进入了房间玩游戏,然后在次日离开房间,对于这类数据在数据库中依然只会记录一条记录,对应其离开房间时间、游戏时长、在线时长。如果我们直接用此记录查询,会出现用户当天在线时长>24小时的现象,业务上我们可以解释为跨天在线(游戏),但在逻辑上当天在线时长>24小时,显然是有问题的。因此我们需要将跨天的记录进行拆分。
用图形描述我们期望达到的效果:

如果起止时间跨天的,我们以0点将其拆分成多条记录,计算各区间的在线时长,然后将游戏时长从起始时间开始填充,游戏时长用完补0。
参考,得到满足需求的处理脚本:

WITH    x0
AS (
       SELECT 'A' AS     Ident
             ,139185  AS PlayTime
             ,DATEADD(SS,-256199,'2016-01-11 20:59:43.243') date_begin
             ,CONVERT(DATETIME ,'2016-01-11 20:59:43.243') AS date_end
             ,256199 AS OnlineTime
       UNION ALL
       SELECT 'B' AS     Ident
             ,6085  AS PlayTime
             ,DATEADD(SS,-6199,'2015-10-18 00:12:42.840') date_begin
             ,CONVERT(DATETIME ,'2015-10-18 00:12:42.840') AS date_end
             ,6199 AS OnlineTime
   ),/*计算两个时间点之间相差的天数*/
x1
AS (
       SELECT Ident
             ,PlayTime
             ,date_begin
             ,date_end
             ,OnlineTime
             ,DATEDIFF(DAY ,date_begin ,date_end) AS cacl_day--开始时间和结束时间相差的天数
       FROM   x0
   ),/*将隔天的时间分解*/
x2        
AS (
       SELECT Ident
             ,PlayTime
             ,CASE
                   WHEN msv.number=0 THEN date_begin
                   ELSE CONVERT(VARCHAR(10) ,DATEADD(DAY ,msv.number ,date_begin) ,120)
              END                 AS date_begin
             ,CASE
                   WHEN msv.number=x.cacl_day THEN date_end
                   ELSE CONVERT(VARCHAR(10) ,DATEADD(DAY ,msv.number ,date_begin) ,120)
                       +' 23:59:59.997'
              END                 AS date_end
             ,OnlineTime
             ,CASE
                   WHEN msv.number=x.cacl_day THEN 1
                   ELSE 0
              END                 AS flag--如果是最后一天,标识为1,否则为0
       FROM   x1 x
             ,MASTER..spt_values     msv
       WHERE  msv.type = 'P'
              AND msv.number<= x.cacl_day
   ),
x3
AS (
       SELECT Ident
             ,PlayTime
             ,date_begin
             ,date_end
             ,OnlineTime
             ,CASE
                   WHEN CONVERT(CHAR(8) ,date_end ,108)='23:59:59' THEN DATEDIFF(SS ,date_begin ,date_end)+1
                   ELSE DATEDIFF(SS ,date_begin ,date_end)
              END AS cacl_OnlineTime
             ,flag
             ,ROW_NUMBER() OVER(PARTITION BY Ident ORDER BY date_end) AS rn--行号
       FROM   x2
   )
SELECT *
      ,CASE 
            WHEN playtime>=(
                     SELECT SUM(cacl_OnlineTime)
                     FROM   x3 x
                     WHERE  x.Ident = x3.Ident
                            AND x.rn<= x3.rn
                 ) THEN cacl_OnlineTime
            WHEN playtime<(
                     SELECT SUM(cacl_OnlineTime)
                     FROM   x3 x
                     WHERE  x.Ident = x3.Ident
                            AND x.rn<= x3.rn
                 )
                 AND playtime>(
                     SELECT ISNULL(SUM(cacl_OnlineTime) ,0)
                     FROM   x3 x
                     WHERE  x.Ident = x3.Ident
                            AND x.rn<x3.rn
                 ) THEN playtime-(
                     SELECT ISNULL(SUM(cacl_OnlineTime) ,0)
                     FROM   x3 x
                     WHERE  x.Ident = x3.Ident
                            AND x.rn<x3.rn
                 )
            ELSE 0
       END cacl_PlayTime
FROM   x3
ORDER BY Ident,date_begin
View Code

数据是能拆分,但如果记录数较多,最好分批处理。如果还要与原数据表中非跨天的记录结合查询,即用拆分好的记录替代原跨天记录,这个消耗也不小。
最近遇到拆分跨天问题,表中跨天数据情况如下:

可以看出,跨1、2天的占了99%,如果用上面的语句每次跑一个用户,测试结果是每1000用户(约5000条记录)拆分需11分钟,对于10W用户需要将近一天时间!
和老大说明处理过程,可能需要很长时间。老大指出可以换种处理方式,以所跨天数为维度,跨一天的拆成开始时间-当天23:59:59,次日0点-结束时间;跨两天拆成开始时间-当天23:59:59,次日0点-次日23:59:59,第三天0点-结束时间...这样就把问题划分成几个大集合,而不是以用户维度的小集合。再把游戏时间从开始时间填充即可。
总思路:将原始数据通过导入导出向导导入到测试库,将跨天的数据insert到测试库,处理跨天数据,从测试库下的原始数据表删除跨天纪录,将拆分好的数据insert到测试库的原始数据表。
待拆分的记录

拆分后的记录

附上代码

--使用导入导出向导 导出原始数据到测试库
SELECT * FROM [SourceDB].[dbo].[RecordUserLeave] (nolock)
WHERE LeaveTime<'20160201'

--跨天数据INSERT到测试库
SELECT [UserID]
      ,[Score]
      ,[Revenue]
      ,[KindID]
      ,[ServerID]
      ,case when [PlayTimeCount]>[OnLineTimeCount] then [OnLineTimeCount]
      else [PlayTimeCount] end [PlayTimeCount]
      ,[OnLineTimeCount]
      ,DATEADD(SS,-OnLineTimeCount,LeaveTime) EnterTime
      ,[LeaveTime]
      ,[deviceType]
      into TargetDB.dbo.RecordUserLeave_Kua
  FROM [SourceDB].[dbo].[RecordUserLeave] (nolock)
  where LeaveTime<'20160201'
  and DATEDIFF(DAY,DATEADD(SS,-OnLineTimeCount,LeaveTime),[LeaveTime])>0

/********跨天数据按天拆分********/
--创建同结构的数据表,保存拆分后的记录
SELECT * INTO RecordUserLeave_KuaFinish FROM TargetDB.dbo.RecordUserLeave_Kua WHERE 1=0
--跨一天(DATEDIFF(day,[EnterTime],[LeaveTime])=1)
--day1
INSERT INTO RecordUserLeave_KuaFinish
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,EnterTime
   ,LeaveTime
   ,deviceType
  )
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
       --,PlayTimeCount,OnLineTimeCount,EnterTime,LeaveTime
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN PlayTimeCount
            ELSE DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)) 
       OnLineTimeCount
      ,EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 1
UNION ALL
--day2
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN 0
            ELSE PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END
      ,DATEDIFF(SS ,CONVERT(VARCHAR(10) ,LeaveTime ,120) ,LeaveTime) 
       OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,LeaveTime ,120)+' 00:00:00.000' EnterTime
      ,LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 1

--跨两天(DATEDIFF(day,[EnterTime],[LeaveTime])=2)
INSERT INTO RecordUserLeave_KuaFinish
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,EnterTime
   ,LeaveTime
   ,deviceType
  )
--day1
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN PlayTimeCount
            ELSE DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)) 
       OnLineTimeCount
      ,EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 2
UNION ALL
--day2
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =1 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 2
UNION ALL
--day3
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=1 THEN 0
            ELSE PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,CONVERT(VARCHAR(10) ,LeaveTime ,120) ,LeaveTime) 
       OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,LeaveTime ,120)+' 00:00:00.000' EnterTime
      ,LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 2

--跨三天(DATEDIFF(day,[EnterTime],[LeaveTime])=3)
INSERT INTO RecordUserLeave_KuaFinish
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,EnterTime
   ,LeaveTime
   ,deviceType
  )
--day1
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN PlayTimeCount
            ELSE DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)) 
       OnLineTimeCount
      ,EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 3
UNION ALL
--day2
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =1 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 3
UNION ALL
--day3
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=1 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =2 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 3
UNION ALL
--day4
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=2 THEN 0
            ELSE PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,CONVERT(VARCHAR(10) ,LeaveTime ,120) ,LeaveTime) 
       OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,LeaveTime ,120)+' 00:00:00.000' EnterTime
      ,LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 3

--跨四天(DATEDIFF(day,[EnterTime],[LeaveTime])=4)
INSERT INTO RecordUserLeave_KuaFinish
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,EnterTime
   ,LeaveTime
   ,deviceType
  )
--day1
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN PlayTimeCount
            ELSE DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)) 
       OnLineTimeCount
      ,EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 4
UNION ALL
--day2
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =1 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 4
UNION ALL
--day3
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=1 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =2 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 4
UNION ALL
--day4
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=2 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =3 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 4
UNION ALL
--day5
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=3 THEN 0
            ELSE PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+4 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,CONVERT(VARCHAR(10) ,LeaveTime ,120) ,LeaveTime) 
       OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,LeaveTime ,120)+' 00:00:00.000' EnterTime
      ,LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 4

--跨五天(DATEDIFF(day,[EnterTime],[LeaveTime])=5)
INSERT INTO RecordUserLeave_KuaFinish
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,EnterTime
   ,LeaveTime
   ,deviceType
  )
--day1
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN PlayTimeCount
            ELSE DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)) 
       OnLineTimeCount
      ,EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5
UNION ALL
--day2
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =0 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =1 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+1 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5
UNION ALL
--day3
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=1 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =2 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+2 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5
UNION ALL
--day4
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=2 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =3 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+3 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5
UNION ALL
--day5
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=3 THEN 0
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                =4 THEN PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+4 ,120))
            ELSE 86400
       END       PlayTimeCount
      ,86400     OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,EnterTime+4 ,120)+' 00:00:00.000' EnterTime
      ,CONVERT(VARCHAR(10) ,EnterTime+4 ,120)+' 23:59:59.997' LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5
UNION ALL
--day6
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,CASE 
            WHEN DATEDIFF(DAY ,EnterTime ,DATEADD(ss ,PlayTimeCount ,EnterTime))
                <=4 THEN 0
            ELSE PlayTimeCount-DATEDIFF(SS ,EnterTime ,CONVERT(VARCHAR(10) ,EnterTime+5 ,120))
       END PlayTimeCount
      ,DATEDIFF(SS ,CONVERT(VARCHAR(10) ,LeaveTime ,120) ,LeaveTime) 
       OnLineTimeCount
      ,CONVERT(VARCHAR(10) ,LeaveTime ,120)+' 00:00:00.000' EnterTime
      ,LeaveTime
      ,deviceType
FROM   [TargetDB].[dbo].[RecordUserLeave_Kua] (nolock)
WHERE  DATEDIFF(DAY ,[EnterTime] ,[LeaveTime]) = 5


--五天以上的用下面语句直接获取
;WITH x1
AS(
      SELECT top 50 * --注意top N取值需>=满足where条件的记录数
            ,DATEDIFF(DAY ,EnterTime ,LeaveTime) cacl_day
      FROM   TargetDB.dbo.RecordUserLeave_Kua (nolock)
      WHERE DATEDIFF(day,[EnterTime],[LeaveTime])>5
  )
,
x2
AS(
      SELECT x.UserID
            ,x.Score
            ,x.Revenue
            ,x.KindID
            ,x.ServerID
            ,x.PlayTimeCount
            --,x.OnLineTimeCount 
            ,EnterTime              EnterTime_old
            ,LeaveTime              LeaveTime_old
            ,CASE 
                  WHEN msv.number=0 THEN EnterTime
                  ELSE CONVERT(VARCHAR(10) ,DATEADD(DAY ,msv.number ,EnterTime) ,120)
             END                 AS EnterTime
            ,CASE 
                  WHEN msv.number=x.cacl_day THEN LeaveTime
                  ELSE CONVERT(VARCHAR(10) ,DATEADD(DAY ,msv.number ,EnterTime) ,120)
                      +' 23:59:59.997'
             END                 AS LeaveTime
            ,x.deviceType
            ,CASE 
                  WHEN msv.number=x.cacl_day THEN 1
                  ELSE 0
             END                 AS flag--如果是最后一天,标识为1,否则为0
      FROM   x1 x
            ,MASTER..spt_values     msv
      WHERE  msv.type = 'P'
             AND msv.number<= x.cacl_day
  )
,
x3
AS(
      SELECT *
            ,CASE 
                  WHEN CONVERT(CHAR(8) ,LeaveTime ,108)='23:59:59' THEN DATEDIFF(SS ,EnterTime ,LeaveTime)
                      +1
                  ELSE DATEDIFF(SS ,EnterTime ,LeaveTime)
             END cacl_OnlineTime
            ,ROW_NUMBER() OVER(PARTITION BY UserID ,EnterTime_Old ORDER BY LeaveTime) AS rn--行号
      FROM   x2
  )
INSERT INTO RecordUserLeave_KuaFinish(UserID,Score,Revenue,KindID,ServerID,EnterTime,LeaveTime,deviceType,OnLineTimeCount,PlayTimeCount)
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,EnterTime
      ,LeaveTime
      ,deviceType
      --,flag
      ,cacl_OnlineTime
      --,rn
      ,CASE
            WHEN PlayTimeCount>=(
                     SELECT SUM(cacl_OnlineTime)
                     FROM   x3 x
                     WHERE  x.UserID = x3.UserID
                            AND x.EnterTime_old = x3.EnterTime_old
                            AND x.rn<= x3.rn
                 ) THEN cacl_OnlineTime
            WHEN PlayTimeCount<(
                     SELECT SUM(cacl_OnlineTime)
                     FROM   x3 x
                     WHERE  x.UserID = x3.UserID
                            AND x.EnterTime_old = x3.EnterTime_old
                            AND x.rn<= x3.rn
                 )
                 AND PlayTimeCount>(
                     SELECT ISNULL(SUM(cacl_OnlineTime) ,0)
                     FROM   x3 x
                     WHERE  x.UserID = x3.UserID
                            AND x.EnterTime_old = x3.EnterTime_old
                            AND x.rn<x3.rn
                 ) THEN PlayTimeCount-(
                     SELECT ISNULL(SUM(cacl_OnlineTime) ,0)
                     FROM   x3 x
                     WHERE  x.UserID = x3.UserID
                            AND x.EnterTime_old = x3.EnterTime_old
                            AND x.rn<x3.rn
                 )
            ELSE 0
       END cacl_PlayTime
FROM   x3
ORDER BY
       UserID
      ,EnterTime


--测试库的原数据表中删除跨天的数据 
DELETE 
FROM   TargetDB.[dbo].[RecordUserLeave]
WHERE  DATEDIFF(DAY ,DATEADD(SS ,-OnLineTimeCount ,LeaveTime) ,[LeaveTime])>0
--将拆分好的数据插入测试库原数据表
INSERT INTO TargetDB.[dbo].[RecordUserLeave]
  (
    UserID
   ,Score
   ,Revenue
   ,KindID
   ,ServerID
   ,PlayTimeCount
   ,OnLineTimeCount
   ,LeaveTime
   ,deviceType
  )
SELECT UserID
      ,Score
      ,Revenue
      ,KindID
      ,ServerID
      ,PlayTimeCount
      ,OnLineTimeCount
      ,LeaveTime
      ,deviceType
FROM   TargetDB.[dbo].RecordUserLeave_KuaFinish
View Code

用后面这种方式,处理拆分跨天数据只需13s

原文地址:https://www.cnblogs.com/Uest/p/5207803.html