MySQL:从彼此关联的2个表中获取最新消息

时间:2018-11-18 14:20:06

标签: mysql sql

首先,非常感谢您的帮助。

我有2个表:conversation表和message表,以及将消息与对话相关联的第三个表assoc_message__conversation

我需要获取针对指定的每个会话发送的最新message_idmessage,以及与之相关的conversation_id

这是一个分贝小提琴:https://www.db-fiddle.com/f/kxRQeGUYYgQ7FTwi96hbLp/0

如本例所示,有conversation_id为1和2的两个对话,并且每个对话有3条消息。消息1、2和3与会话1相关联,消息4、5和6与会话2相关联。

我需要能够在conversation_id表(ID 1和2)中指定assoc_message__conversation,并检索最新的message_idmessage和从conversation_id表发送的与指定的每次会话相关联的message

所以它应该拉的行是:

conversation_id | message_id | message
------------------------------------------------
              1 |          3 | "Latest message"
------------------------------------------------
              2 |          6 | "Latest message"
------------------------------------------------

非常感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

在旧版的MySQL(<8.0.2)中,我们可以使用Derived Tables。在派生表中,我们可以获取每个send_datetime的最新conversation_id值。 此外,值得注意的是,您可以在此子查询的WHERE子句中为session_id提供过滤器。

然后我们可以使用该子查询的结果集,并适当地返回主表,以获取与会话中最新消息相对应的行。

模式(MySQL v5.7)

View on DB Fiddle

查询#1

SELECT
  amc.conversation_id, 
  m.message_id, 
  m.message   
FROM 
  assoc_message__conversation AS amc
JOIN message AS m 
  ON m.message_id = amc.message_id 
JOIN 
(
  SELECT
    amc1.conversation_id, 
    MAX(m1.send_datetime) AS latest_send_datetime
  FROM
   assoc_message__conversation AS amc1
  JOIN message AS m1
    ON m1.message_id = amc1.message_id 
  WHERE amc1.conversation_id IN (1,2)  -- Here you provide your input filters
  GROUP BY amc1.conversation_id
) AS dt  
  ON dt.conversation_id = amc.conversation_id AND 
     dt.latest_send_datetime = m.send_datetime;

结果

| conversation_id | message_id | message        |
| --------------- | ---------- | -------------- |
| 1               | 3          | Latest message |
| 2               | 6          | Latest message |

在MySQL 8.0.2及更高版本中,我们可以使用Row_Number()功能。在conversation_id的分区中,我们将确定每个消息的行号,并按send_datetime的降序排列。 在此子查询中,您可以在WHERE子句中提供针对session_id的过滤器。

然后,我们将此结果集用作派生表,并仅考虑行号值为1的那些行(因为它将属于最新的send_datetime)。

模式(MySQL v8.0)

View on DB Fiddle

查询#2

SELECT 
  dt.conversation_id, 
  dt.message_id, 
  dt.message 
FROM 
(
  SELECT
    amc.conversation_id, 
    m.message_id, 
    m.message, 
    ROW_NUMBER() OVER (PARTITION BY amc.conversation_id 
                       ORDER BY m.send_datetime DESC) AS row_no 
  FROM
   assoc_message__conversation AS amc
  JOIN message AS m
    ON m.message_id = amc.message_id 
  WHERE amc.conversation_id IN (1,2)  -- Here you provide your input filters
) AS dt  
WHERE dt.row_no = 1;

结果

| conversation_id | message_id | message        |
| --------------- | ---------- | -------------- |
| 1               | 3          | Latest message |
| 2               | 6          | Latest message |

答案 1 :(得分:0)

假设每条新消息增加amc_id,我将在where子句中建议一个相关的子查询:

select amc.*, m.message
from message m join
     assoc_message__conversation amc
     on amc.message_id = m.message_id
where amc.amc_id = (select max(amc.amc_id)
                    from assoc_message__conversation amc2
                    where amc2.conversation_id = amc.conversation_id
                   );

如果您实际上需要使用send_datetime,则需要另外使用join

where m.send_datetime = (select max(m2.send_datetime)
                         from message m2 join
                              assoc_message__conversation amc2
                              on amc2.message_id = m2.message_id
                         where amc2.conversation_id = amc.conversation_id
                        )