会话中的最新消息-合并多个SQL语句

时间:2018-07-14 01:50:10

标签: sql sql-server linq

我正在处理一个收件箱应用程序,并且有一个名为Messages的表,其中包含用户之间发送的所有消息。我们将其设置为对话视图。如果您答复一条消息,则第一条消息的消息ID成为所有后续答复的parentMessageID。它有几个领域,但是为此,我实际上只关心其中三个领域。带有示例数据的基本设置是:

MessageID (Guid)   |   Date     |  ParentMessageID (Guid)   | recipientID
  00000000           07/11/18         NULL                       1
  11111111           07/12/18         00000000                   2
  22222222           07/10/18         NULL                       2
  33333333           07/11/18         22222222                   1
  44444444           07/01/18         NULL                       2
  • 我知道GUID缩短了,只是使它更容易安装在一行上。

现在我有以下内容:

Select * from messages where recipientID = X AND ParentMessageID is null Order by Date DESC

这些结果将变成一个列表。此后,我遍历邮件列表,并检查是否有子邮件带有

Select top 1 * from messages where parentMessageID = X order by date desc

如果产生结果,则只需将列表中的父邮件替换为我刚刚找到的子邮件。效果很好...但是我需要能够将其转换为一个SQL查询以用于缓存,以便可以使用.Skip和.Take进行分页。

我没有运气就尝试了不同的join和group by语句,而且一旦弄清楚了,我必须确保它可以与LINQ一起使用。我们正在使用SQL Server 17。

如果使用以上数据作为参考,则期望结果集将是收件人ID 2:

MessageID (Guid)   |   Date     |  ParentMessageID (Guid)   | recipientID
  11111111           07/12/18         00000000                   2
  44444444           07/01/18         NULL                       2

对于收件人1:

MessageID (Guid)   |   Date       |  ParentMessageID (Guid)  | recipientID
  00000000           07/11/18 2:00        NULL                       1
  33333333           07/11/18 1:20        22222222                   1

1 个答案:

答案 0 :(得分:0)

弄清楚如何仅使用最新的子消息后,我想到了以下解决方案:

DECLARE @X int = 2;

WITH
  MsgChildNumbering (MsgID, [Date], ParentMsgID, RcptID, ChildNo) AS (
    SELECT MessageID, [Date], ParentMessageID, RecipientID
      , ROW_NUMBER() OVER (PARTITION BY ParentMessageID ORDER BY [Date] DESC)
    FROM Messages 
  ),
  CTE_Msg (MsgID, [Date], ParentMsgID, RcptID, RootMsgID, LevelNo) AS (
    SELECT MsgID, [Date], ParentMsgID, RcptID, MsgID, 1
    FROM MsgChildNumbering WHERE ParentMsgID IS NULL AND RcptID = @X
    UNION ALL
    SELECT c.MsgID, c.[Date], c.ParentMsgID, c.RcptID, p.RootMsgID, 1+p.LevelNo
    FROM MsgChildNumbering AS c -- child messages with numbering
      INNER JOIN CTE_Msg AS p -- parent messages from last iteration
        ON c.ParentMsgID = p.MsgID
    WHERE c.ChildNo = 1
  ),
  MsgNumbering (MsgID, [Date], ParentMsgID, RcptID, MsgNo) AS (
    SELECT MsgID, [Date], ParentMsgID, RcptID
      , ROW_NUMBER() OVER (PARTITION BY RootMsgID ORDER BY LevelNo DESC)
    FROM CTE_Msg
  )
SELECT MsgID, [Date], ParentMsgID, RcptID
FROM MsgNumbering WHERE MsgNo = 1;
  • CTE MsgChildNumbering 用于创建子代的编号,以便每个父代只能添加最新的子代。
  • CTE_Msg 是递归部分,它从与收件人@X进行对话的所有初始消息开始,然后依次与ChildNo = 1添加子消息(每个子消息中只有最新的父)。
  • 最后,CTE MsgNumbering 通过RootMsgID对会话中的消息添加反向编号(与LevelNo相同),以便能够找到每个会话的最新消息。