SQL Server Select记录分组

时间:2017-02-15 18:47:24

标签: sql-server select grouping

我有一个“聊天”应用程序,我们在其中有一组用户之间的聊天。因此,一个用户可以成为多个组的一部分。

用户登录后,我们必须显示所有用户组及其消息。

但是,我们在登录时为每个群组消息提供了100个消息的桶/限制。意味着我们将为每个组仅向用户显示100条消息(最新消息),并显示其余消息,其中有一个按钮“加载早期消息”。

但是这100条消息的限制可能会在以下情况的基础上发生变化 -

  1. 如果每个组的所有消息都是Read,我们只需要显示100条消息(根据桶大小)。

  2. 我们必须显示每个组的所有UnRead消息,没有未读消息的存储桶。

  3. 最后一个场景是Read& UnRead消息。

    • 如果有> = 100条未读消息和一些阅读消息,那么我们只会显示所有UnRead消息。因为它(UnRead消息)超过了桶大小,我们不能在这里显示Read消息。
    • 如果有50条UnRead消息和50条Read消息,那么我们可以显示所有消息,因为它不超过桶大小。
    • 如果有60条UnRead和50条Read消息,那么我们必须显示100条消息,其中60条消息为UnRead,40条为Read消息。
  4. 因此,根据上述情况,我们必须在所有情况下显示所有UnRead消息是否超过桶大小。

    以下是我们正在使用的表格 -

    (1) Group表:

       GroupId(PK)            GroupName
        g1                      Group_A
        g2                      Group_B
        g3                      Group_C
        g4                      Group_D
        g5                      Group_E
    

    (2) ChatMessage(此处GroupId为FKey)

      ChatMessageId(PK)  GroupId(FK)  Message   CreatedDate
      m1                   g1          hi       25 Jan, 2017
      m2                   g2          hi1      26 Jan, 2017
      m3                   g1          hi2      25 Jan, 2017
      m4                   g1          hi3      25 Jan, 2017  
      m5                   g3          hi4      27 Jan, 2017
      m6                   g4          hi5      28 Jan, 2017
      m7                   g5          hi6      29 Jan, 2017
      m8                   g2          hi7      26 Jan, 2017
      m9                   g3          hi8      27 Jan, 2017
      m10                  g4          hi9      30 Jan, 2017
    

    (3) ChatMessageMember(ChatMessageId和GroupId是FKey在这里)

     MemberId  ChatMessageId  GroupId   UserId  ISMessageRead   CreatedDate
     cm1                m1       g1     111      Yes            25 Jan, 2017
     cm2                m1       g1     222      Yes            25 Jan, 2017
     cm3                m2       g2     111      No             26 Jan, 2017
     cm4                m2       g2     222      Yes            26 Jan, 2017
     cm5                m3       g1     111      No             25 Jan, 2017
     cm6                m3       g1     222      Yes            25 Jan, 2017
     cm7                m4       g1     111      No             25 Jan, 2017
     cm8                m4       g1     222      Yes            25 Jan, 2017
     cm9                m5       g3     111      Yes            27 Jan, 2017
     cm10               m5       g3     222      Yes            27 Jan, 2017
     cm11               m6       g4     111      No             25 Jan, 2017
     cm12               m6       g4     222      No             25 Jan, 2017
     cm13               m7       g5     111      No             29 Jan, 2017
     cm14               m7       g5     222      No             29 Jan, 2017
     cm15               m8       g2     111      Yes            26 Jan, 2017
     cm16               m8       g2     222      Yes            26 Jan, 2017
     cm17               m9       g3     111      Yes            27 Jan, 2017
     cm18               m9       g3     222      Yes            27 Jan, 2017
     cm19               m10      g4     111      Yes            30 Jan, 2017
     cm20               m10      g4     222      Yes            30 Jan, 2017
    

    我们使用以下标准来获取记录 -

    select cmm.* 
    from ChatMessageMember cmm
    where UserId =  111 and CreatedDate <= '31 Jan, 2017'
    

    所以根据上面的查询记录应该基于“UserId”和给定的“Date”。这里我们使用CreatedDate作为endTime意味着我们必须选择记录直到DateTime。但对于起点,我们有两种情况 -

    1. 让我们从结束时间开始,所以起点将是第100条记录,但如果第100条记录是“UnRead”,那么我们必须选择记录,直到序列中的最后一条“UnRead”记录(直到我们没有得到任何记录) “阅读”记录。

    2. 但如果我们在第100个位置找到任何“阅读”记录,那么这将是我们的起点。

    3. 在这个我必须处理查询性能的复杂场景中,有人可以帮助我。

      仅供参考,我使用的是SQL Server 2012和VS 2015.

      更新 有关输出,请查看以下方案 -

      please check the below table. For ex the bucket/limit is 3 and CreatedDate
      is  "30 Jan, 2017". So according to limit and Date filter the messages  
      should be m7,m6 & m5 for group 1 (g1). But there is an "UnRead" messages  
      ahead after 3 messages (at position m4 & m2). So we have to pick records 
      till last "UnRead" message from CreatedDate. Means from m7 to m2. So 
      messages will be (m2,m3,m4,m5,m6,m7).
      
      
      Message             IsMessageRead          GroupId         CreatedDate
       m1                    yes                   g1            26 Jan, 2017
       m2                    no                    g1            27 Jan, 2017
       m3                    yes                   g1            27 Jan, 2017
       m4                    no                    g1            27 Jan, 2017
       m5                    no                    g1            27 Jan, 2017
       m6                    yes                   g1            27 Jan, 2017
       m7                    no                    g1            28 Jan, 2017
      

1 个答案:

答案 0 :(得分:0)

WITH
    messages (row_number, memberid, chatmessageid, groupid, userid, ismessageread, createddate) AS
    (
        SELECT 
            ROW_NUMBER() OVER (ORDER BY ismessageread ASC) rn
            , memberid
            , chatmessageid
            , groupid
            , userid
            , ismessageread
            , createddate 
        FROM
            ChatMessageMember cmm
        WHERE 
            UserId =  111 
            AND CreatedDate <= '31 Jan, 2017'
    ),
    messages_summary (num_unread) AS
    (
        SELECT 
            SUM(CASE WHEN ismessageread = 'No' THEN 1 ELSE 0 END) num_unread
        FROM 
            messages
    )
SELECT
    *
FROM
    messages
WHERE
    rn <= (
        SELECT 
            CASE WHEN num_unread > 100 THEN num_unread ELSE 100 END num_messages_to_return 
        FROM 
            messages_summary
    )