首页 > 其他 > 详细

拆分跨天的时间数据

时间:2016-02-22 22:10:05      阅读:226      评论:0      收藏:0      [点我收藏+]

数据表记录了用户每次离开房间时的离开时间、游戏时长、在线时长,现在需统计用户每天的在线时长数据。现实中存在用户前一天进入了房间玩游戏,然后在次日离开房间,对于这类数据在数据库中依然只会记录一条记录,对应其离开房间时间、游戏时长、在线时长。如果我们直接用此记录查询,会出现用户当天在线时长>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

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

拆分跨天的时间数据

原文:http://www.cnblogs.com/Uest/p/5207803.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!