我有一个非常基本的聊天应用程序,有两张桌子:UsersMessages.这两个表都做了它们在TIN上所说的事情:)当一个用户向另一个用户发送消息时,我在Messages表上记录了userID(消息发送者)和userIDReceived(消息接收者).

有关数据如下:

table : Users
+-------+-----------+
|userID | username  |
+-------+-----------+
|    1  |    John   |
|    2  |    Mary   |
|    3  |    Jeff   |
|    4  |    Bill   |
|    5  |    Bob    |
+-------+-----------+

table : Messages
+---------+-----------+--------------+------------===----+
|messageID|    userID |userIDReceived|        created    |
+---------+-----------+--------------+-------------------+
|    1    |    1      |        2     |2024-02-01 19:55:37|
|    2    |    1      |        2     |2024-02-01 17:20:10|
|    3    |    2      |        3     |2024-02-01 19:27:18|
|    4    |    3      |        1     |2024-01-16 17:46:57|
|    5    |    3      |        1     |2024-01-26 02:34:44|
+---------+-----------+--------------+-------------------+

我对这些表进行了标准化,以便将用户数据存储在Users表中,而将消息数据存储在Messages表中.我try 做的是对特定用户(按userID)发送和接收的所有消息进行分组,以便仅返回最后发送和/或接收的消息.

下面是我的查询示例,其中userID 1正在try 获取任何其他用户发送给他的最后一条消息:

SELECT DISTINCT 'sent' AS direction, u.userID, u.username, MAX(m.messageID), MAX(m.created), m.message
FROM Messages m
LEFT JOIN Users u
ON m.userIDReceived = u.userID
WHERE m.userID = 1
GROUP BY m.userIDReceived 
UNION
SELECT DISTINCT 'received' AS direction, u.userID, u.username, MAX(m.messageID), MAX(m.created), m.message
FROM Messages m
LEFT JOIN Users u
ON m.userID = u.userID
WHERE m.userIDReceived = 1
GROUP BY m.userID;

查询可以工作,但是返回的"Message"值总是不正确的--它似乎总是显示在两个用户之间发送的第一条消息.我似乎无法将MAX()应用于Message列(因为它是一个文本字段,因此try 对其进行排序是毫无意义的),或者将ORDER BY应用于返回的日期以显示正确的消息值.

I want my result to look like this:
+---------+-----------+--------------+------------===----+---------+
|messageID|    userID |username|        created          |message  |
+---------+-----------+--------------+-------------------+---------+
|sent     |    1      |        2     |2024-02-01 19:55:37|Hey there|
|sent     |    1      |        2     |2024-02-01 17:20:10|Hi       |
|sent     |    2      |        3     |2024-02-01 19:27:18|How      |
|received |    3      |        1     |2024-01-16 17:46:57|Yeah good|
|received |    3      |        1     |2024-01-26 02:34:44|Cool     |
+---------+-----------+--------------+-------------------+---------+

请注意,实际上并不需要返回列messageID;我只是想用它来解决这个查询问题.

此外,服务器版本为5.7.44-cll-lve-mySQL社区服务器-(GPL)

有什么主意吗?

推荐答案

确保该子查询 for each 会话返回最大时间戳为created的整行,然后将此结果连接回Messages表,以获得实际的消息文本:

WITH LastMessage AS (
    SELECT userID, userIDReceived, MAX(created) AS MaxCreated
    FROM Messages
    WHERE userID = 1 OR userIDReceived = 1
    GROUP BY userID, userIDReceived
)
SELECT 'sent' AS direction, u.userID, u.username, lm.MaxCreated, m.message
FROM LastMessage lm
JOIN Messages m ON lm.userID = m.userID AND lm.userIDReceived = m.userIDReceived AND lm.MaxCreated = m.created
LEFT JOIN Users u ON m.userIDReceived = u.userID
WHERE m.userID = 1
UNION ALL
SELECT 'received' AS direction, u.userID, u.username, lm.MaxCreated, m.message
FROM LastMessage lm
JOIN Messages m ON lm.userID = m.userID AND lm.userIDReceived = m.userIDReceived AND lm.MaxCreated = m.created
LEFT JOIN Users u ON m.userID = u.userID
WHERE m.userIDReceived = 1;

Edit

OP告诉他的MySQL版本是5.7,即CTE不可用.

使用子查询而不是CTE.

SELECT 'sent' AS direction, u.userID, u.username, lm.MaxCreated, m.message
FROM (
    SELECT userID, userIDReceived, MAX(created) AS MaxCreated
    FROM Messages
    WHERE userID = 1 OR userIDReceived = 1
    GROUP BY userID, userIDReceived
) AS lm
JOIN Messages m ON lm.userID = m.userID AND lm.userIDReceived = m.userIDReceived AND lm.MaxCreated = m.created
LEFT JOIN Users u ON m.userIDReceived = u.userID
WHERE m.userID = 1
UNION ALL
SELECT 'received' AS direction, u.userID, u.username, lm.MaxCreated, m.message
FROM (
    SELECT userID, userIDReceived, MAX(created) AS MaxCreated
    FROM Messages
    WHERE userID = 1 OR userIDReceived = 1
    GROUP BY userID, userIDReceived
) AS lm
JOIN Messages m ON lm.userID = m.userID AND lm.userIDReceived = m.userIDReceived AND lm.MaxCreated = m.created
LEFT JOIN Users u ON m.userID = u.userID
WHERE m.userIDReceived = 1;

修改自>;Here is an example of my query where userID 1 is trying to get the last message sent to him by any other user:

SELECT 'sent' AS direction, m1.userID, u.username, m1.messageID, m1.created, m1.message
FROM Messages m1
JOIN Users u ON m1.userIDReceived = u.userID
WHERE m1.userID = 1
AND NOT EXISTS (
    SELECT 1 FROM Messages m2
    WHERE m2.userID = m1.userID
    AND m2.userIDReceived = m1.userIDReceived
    AND m2.created > m1.created
)
UNION ALL
SELECT 'received' AS direction, m1.userID, u.username, m1.messageID, m1.created, m1.message
FROM Messages m1
JOIN Users u ON m1.userID = u.userID
WHERE m1.userIDReceived = 1
AND NOT EXISTS (
    SELECT 1 FROM Messages m2
    WHERE m2.userID = m1.userID
    AND m2.userIDReceived = m1.userIDReceived
    AND m2.created > m1.created
);

Mysql相关问答推荐

MYSQL子查询

JOOQ-如何在一个查询中引用多个(但不是所有)表中的所有字段

了解MySQL_stmt_BIND_NAMED_Param()-MySQL C API

递归查询意外地为一个字段返回空值

带有值分隔的MySQL分组不起作用

PythonAnywhere中SSH到MySQL数据库无限期挂起,SSH正确,workbench可以完美连接

将 Cloud Function (nodejs) 连接到 CloudSQL mySQL 数据库

如何在Mysql中使用With和Values

MySQL CHECK 约束以确保记录不使用自动增量 ID 引用自身?

SQL:如何为给定组中的所有记录 Select 一列与另一列不匹配的位置

判断一列中的多个值并返回值 1 或 0

如何在每个国家/地区查询 GHTorrent(类 SQL 语言)的最常用语言

MySQL 每组最大 n 只适用于多行

MySQL如何通过外键ID Select 多行?

我在查询中没有得到正确的结果

在 MySQL 中 Select COUNT of MAX

mysqli_fetch_array() 期望参数 1 为 mysqli_result,布尔值

ON UPDATE RESTRICT 有什么作用?

在 Ubuntu 上安装 mysql gem 的困难

MySQL连接查询使用like?