SQL Server 2008:如何选择两个连续会话之间的差异小于10分钟的所有会话的总和

时间:2013-08-04 19:12:12

标签: sql sql-server sql-server-2008

我有一个存储用户聊天消息的表。每个消息都记录在此表中。我必须计算特定用户的聊天持续时间。

由于用户可能在x​​时间聊天,并且在x + 10次后他离开聊天。在X + 20时间之后,用户再次开始聊天。因此,不应考虑x + 10和x + 20之间的时间段。

表格结构和样本数据如图所示。不同的颜色代表同一用户的两个聊天会话。我们可以看到在663和662之间存在超过1小时的差异,因此应该从结果集中排除这些会话。最终结果应该是2.33分钟。

enter image description here

declare @messagetime1 as datetime
declare @messagetime2 as datetime
select @messagetime1=messagetime from tbl_chatMessages where ID=662
select @messagetime2=messagetime from tbl_chatMessages where ID=659
print datediff(second,@messagetime2,@messagetime1)
   Result --- 97 seconds

declare @messagetime3 as datetime
declare @messagetime4 as datetime
select @messagetime3=messagetime from tbl_chatMessages where ID=668
select @messagetime4=messagetime from tbl_chatMessages where ID=663
print datediff(second,@messagetime4,@messagetime3)
   Result -- 43 seconds

请建议一个计算聊天时间的解决方案。这是我能想到的逻辑之一,以防你们中的任何一个人有更好的想法。请与解决方案分享

5 个答案:

答案 0 :(得分:2)

首先需要计算相邻消息之间的差距,如果差距超过600秒,那么这些消息之间的时间为0

SELECT SUM(o.duration) / 60.00 AS duration
FROM dbo.tbl_chatMessages t1
  OUTER APPLY (
               SELECT TOP 1 
                 CASE WHEN DATEDIFF(second, t2.messageTime, t1.messageTime) > 600
                      THEN 0 
                      ELSE DATEDIFF(second, t2.messageTime, t1.messageTime) END
               FROM dbo.tbl_chatMessages t2
               WHERE t1.messageTime > t2.messageTime
               ORDER BY t2.messageTime DESC
               ) o(duration)

请参阅SQLFiddle

上的演示

答案 1 :(得分:0)

尝试这样的事情:

WITH DATA 
     AS (SELECT t1.*, 
                CASE 
                  WHEN 
        Isnull(Datediff(MI, t2.MESSAGETIME, t1.MESSAGETIME), 11) > 10 
                   THEN 0 
                  ELSE 1 
                END first_ident 
         FROM   TABLE1 t1 
                LEFT JOIN TABLE1 t2 
                       ON t1.ID = t2.ID + 1), 
     CTE 
     AS (SELECT ID, 
                MESSAGETIME, 
                ID gid, 
                0  AS tot_time 
         FROM   DATA 
         WHERE  FIRST_IDENT = 0 
         UNION ALL 
         SELECT t1.ID, 
                t1.MESSAGETIME, 
                t2.GID, 
                t2.TOT_TIME 
                + Datediff(MI, t2.MESSAGETIME, t1.MESSAGETIME) 
         FROM   DATA t1 
                INNER JOIN CTE t2 
                        ON t1.ID = t2.ID + 1 
                           AND t1.FIRST_IDENT = 1) 
SELECT GID, 
       Max(TOT_TIME) Tot_time 
FROM   CTE 
GROUP  BY GID 

我在SQL Fiddle上设置了一个工作示例。如果您有任何问题,请查看并告诉我。

答案 2 :(得分:0)

以下是我的解决方案背后的原因。首先,确定开始聊天时段的每个聊天。您可以使用标记来标记距离上一次聊天超过10分钟的聊天。

然后,拿这个标志做一个累积的总和。该总和实际上用作聊天时段的分组标识符。最后,汇总结果以获取每个聊天时段的信息。

with cmflag as (
      select cm.*,
             (case when datediff(min, prevmessagetime, messagetime) > 10
                   then 0
                   else 1
              end) as ChatPeriodStartFlag
      from (select cm.*,
                   (select top 1 messagetime
                    from tbl_chatMessages cm2
                    where cm2.senderId = cm.senderId or
                          cm2.RecipientId = cm.senderId
                   ) as prevmessagetme
            from tbl_chatMessages cm
           ) cm
     ),
     cmcum as (
      select cm.*,
             (select sum(ChatPeriodStartFlag)
              from cmflag cmf
              where cm2.senderId = cm.senderId or
                    cm2.RecipientId = cm.senderId and
                    cmf.messagetime <= cm.messagetime
             ) as ChatPeriodGroup
      from tbl_chatMessages cm
     )
select cm.SenderId, ChatPeriodGroup, min(messageTime) as mint, max(messageTime) as maxT
from cmcum
group by cm.SenderId, ChatPeriodGroup;

我可能无法完全理解的一个挑战是如何在发件人和收件人之间进行匹配。样本数据中的所有行都具有相同的对。这是从SenderId角度查看“用户”,但考虑到在聊天期间,用户可以是发件人或收件人。

答案 3 :(得分:0)

您可以使用此查询(here):

DECLARE @Results TABLE(
  RowNum INT NOT NULL,
  senderID INT NOT NULL DEFAULT(80),
  recipientID INT NOT NULL DEFAULT(79),
    PRIMARY KEY(RowNum,senderID,recipientID),
  messageTime DATETIME NOT NULL
);
INSERT INTO @Results(RowNum,senderID,recipientID,messageTime)
SELECT  ROW_NUMBER() OVER(PARTITION BY senderID,recipientID ORDER BY messageTime, ID) AS RowNum,
        c.senderID,c.recipientID,c.messageTime
FROM    dbo.tbl_chatMessages c;

WITH RecursiveCTE
AS(
    SELECT  crt.RowNum,crt.senderID,crt.recipientID,
            crt.messageTime,
            1 AS SessionID
    FROM    @Results crt
    WHERE   crt.RowNum=1
    UNION ALL
    SELECT  crt.RowNum,crt.senderID,crt.recipientID,
            crt.messageTime,
            CASE 
                WHEN DATEDIFF(MINUTE,prev.messageTime,crt.messageTime) <= 10  THEN prev.SessionID
                ELSE prev.SessionID+1
            END
    FROM    @Results crt INNER JOIN RecursiveCTE prev ON crt.RowNum=prev.RowNum+1
    AND     crt.senderID=prev.senderID
    AND     crt.recipientID=prev.recipientID
)
SELECT  *,
        STUFF(CONVERT(VARCHAR(8), DATEADD(SECOND,x.SessionDuration,0), 114), 1,3,'') AS SessionDuration_mmss,
        SUM(x.SessionDuration) OVER() AS SessionDuration_Overall,
        STUFF(CONVERT(VARCHAR(8), DATEADD(SECOND,SUM(x.SessionDuration) OVER(),0), 114), 1,3,'') AS SessionDuration_Overall_mmss
FROM(
    SELECT  r.senderID,r.recipientID,r.SessionID, 
            DATEDIFF(SECOND, MIN(r.messageTime),MAX(r.messageTime)) AS SessionDuration
    FROM    RecursiveCTE r
    GROUP BY r.senderID,r.recipientID,r.SessionID
) x
OPTION(MAXRECURSION 0);

结果:

senderID recipientID SessionID   SessionDuration SessionDuration_mmss SessionDuration_Overall SessionDuration_Overall_mmss
-------- ----------- ----------- --------------- -------------------- ----------------------- ----------------------------
80       79          1           97              01:37                140                     02:20
80       79          2           43              00:43                140                     02:20

答案 4 :(得分:0)

我专注于对表结构进行细微修改并更新聊天服务器应用程序代码(如果可能的话)。

每次超过X分钟的消息之间有延迟时,您是否可以让聊天服务器生成新的聊天ID?如果是,那么计算聊天持续时间将变得非常容易。