在 SQL 中选择发送者和接收者之间的最后一条消息
Posted
技术标签:
【中文标题】在 SQL 中选择发送者和接收者之间的最后一条消息【英文标题】:Select last message between a sender and a receiver in SQL 【发布时间】:2021-01-13 14:10:55 【问题描述】:我目前正在尝试获取数据库中的最后一条消息,以便创建与其他消息系统(如 Facebook Messenger 或 WhatsApp)类似的系统,但我想获取发件人“对话”的最后一条消息ID (id_emmeteur_id) 和接收者 ID (id_destinataire_id)。
问题是我只成功获取了所有消息,并且我想根据连接的用户只获取两个用户之间的最后一条消息(连接的一个和另一个,取决于我的 ID在我的消息表中有)。
我将我的“消息”表结构与一些示例放在下面,希望对您有所帮助。
id|id_emmeteur_id|id_destinataire_id|contenu
--------------------------------------------
1| 3| 1|test
2| 3| 1|another test
3| 1| 3|test number 3
4| 1| 2|another user
通过这些示例,从逻辑上讲,我应该(如果连接的用户的 ID 为“1”)消息“test number 3”和“another user”,因为 ID 为“1”和 ID 的用户之间的最后一条消息“3”是“3 号测试”,因为“另一个用户”是 ID 为“1”和 ID 为“2”的用户之间的唯一消息,但我认为我的查询不正确。我也会把我找到的查询放在上面,以防它对你有帮助。
select *
from message
where id_destinataire_id=3
or id_emmeteur_id=1
AND ( id, least(id_emmeteur_id, id_destinataire_id), greatest(id_emmeteur_id, id_destinataire_id))
in
( select
max(id)
, least(id_emmeteur_id, id_destinataire_id)
, greatest(id_emmeteur_id, id_destinataire_id)
from message
group by id_emmeteur_id, id_destinataire_id
)
提前感谢您的帮助。 (希望我的数据库结构没有错)
【问题讨论】:
【参考方案1】:你可以使用not exists
如下:
select t.*
from your_table t
where 1 in (t.id_emmeteur_id, t.id_destinataire_id)
and not exists
(select * from your_table tt
where t.id_emmeteur_id = tt.id_emmeteur_id
and t.id_destinataire_id = tt.id_destinataire_id)
and tt.id > t.id)
【讨论】:
感谢您的回答。我已经尝试过您的解决方案,但我只有最新消息(即“另一个用户”)而不是之前的消息。也许我误解了我的问题。使用我提出的问题的示例,我想要消息“另一个用户”(我可以使用您的解决方案)和“测试号 3”(但不幸的是,此消息未被检索)。 这似乎更好,但我有不止一条关于 ID 的“1”和“3”的消息。我会尝试使用您更新的解决方案。也许如果我可以在此查询中的某处放置一个 LIMIT 子句,是否可以每个用户 ID 只有一条消息?【参考方案2】:一种方法是通过 to 和 from id 获取最后一个对话,并基于此过滤结果。
WITH LastMessages AS
(
SELECT
id,
ROW_NUMBER()OVER(PARTITION BY id_destinataire_id ORDER BY ID) last_destinataire_id,
ROW_NUMBER()OVER(PARTITION BY id_emmeteur_id ORDER BY ID) last_emmeteur_id,
id_destinataire_id to_id,
id_emmeteur_id from_id
contenu
FROM
message
WHERE
id_emmeteur_id = 3 OR id_destinataire_id = 3
)
SELECT
id, to_id, from_id, contenu
FROM
LastMessages
WHERE
last_destinataire_id = 1 OR last_emmeteur_id = 1
ORDER BY
id;
无 CTE 版本
SELECT
id,
to_id,
from_id,
contenu
FROM
(
SELECT
id,
last_destinataire_id = ROW_NUMBER()OVER(PARTITION BY id_destinataire_id ORDER BY ID),
last_emmeteur_id = ROW_NUMBER()OVER(PARTITION BY id_emmeteur_id ORDER BY ID),
to_id = id_destinataire_id,
from_id = id_emmeteur_id,
contenu
FROM
message
WHERE
id_emmeteur_id = 3 OR id_destinataire_id = 3
)AS X
WHERE
last_destinataire_id = 1 OR last_emmeteur_id = 1
ORDER BY
id
【讨论】:
我忘了准确地说我正在使用 mysql(我想是的)和 phpMyAdmin(它是一个 Web 项目),并且在我的情况下不支持 WITH 子句。是否可以使用 WITH 以外的其他子句?另外,谢谢您的回答。 使用非 CTE 解决方案更新 我实际上正在寻找如何升级我的 MySQL 版本(我使用的是 5.7 版本),因为我认为“ROW_NUMBER()”函数仅适用于 8.0 或更高版本。我正在使用 MAMP 打开本地服务器,但似乎他们无法升级到比 5.7 更好的版本。我实际上专注于如何升级到 8.0 版本(如果可能的话),我会告诉你我是否找到了适合我的解决方案。再次感谢您的帮助。 你好。我回到这里是因为我无法升级我的 MySQL 版本。我还读到 ROW_NUMBER() 与我的想法不同,它与 MySQL 不兼容。我试图用我将在下面发布的代码“模拟”一个行号,但没有成功。 MySQL 5.7 版本还有另一种可能性吗?很抱歉给您带来不便。 实际SQL查询:SET @rownumber = 0; SELECT id, to_id, from_id, contenu FROM ( SELECT id, (@rownumber:=@rownumber+1) AS last_destinataire_id ORDER BY ID, (@rownumber:=@rownumber+1) AS last_emmeteur_id ORDER BY ID, to_id = id_destinataire_id, from_id = id_emmeteur_id, contenu FROM message WHERE id_emmeteur_id = 3 OR id_destinataire_id = 3 )AS X WHERE last_destinataire_id = 1 OR last_emmeteur_id = 1 ORDER BY id
以上是关于在 SQL 中选择发送者和接收者之间的最后一条消息的主要内容,如果未能解决你的问题,请参考以下文章
MySQL - 根据字段选择LEFT JOIN列的最后几行。