这可以在一个快速 mysql 查询中实现吗?
Is this possible in one fast mysql query?
我有三个 table,我需要他们的不同数据。遗憾的是,我还需要能够提取最新的行。
这是我的 tables:
消息:我只是将消息的内容存储在一个table中,因为一个文本可以发送给多个用户
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| message_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| content | varchar(255) | NO | | 0 | |
+------------+------------------+------+-----+---------+----------------+
对话:这个table只是反映了两个用户之间的一次对话。
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| partner_id | int(10) unsigned | NO | MUL | NULL | |
| conversation_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| expedition_id | int(11) | NO | | NULL | |
| active | tinyint(4) | NO | | 1 | |
+-----------------+------------------+------+-----+---------+----------------+
conversation_messages:table 存储有关实际消息交换的信息。
+-----------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+-------+
| message_id | int(11) unsigned | NO | PRI | NULL | |
| receiver_id | int(11) unsigned | NO | PRI | NULL | |
| conversation_id | int(11) unsigned | NO | MUL | NULL | |
| status | tinyint(4) | NO | | NULL | |
| timestamp | datetime | YES | | NULL | |
+-----------------+------------------+------+-----+---------+-------+
我现在想做的是 select 每个对话中的最新消息,并从该消息中获取内容。 (听起来很简单,但是并没有找到简单的解决方法)。我尝试的是以下内容:
SELECT max(c_m.message_id), m.content, c_m.`status`
FROM expedition_conversations e_c, conversation_messages c_m
INNER JOIN messages m ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1 AND (c_m.conversation_id = e_c.conversation_id)
GROUP BY c_m.conversation_id;
可悲的是,由于 GROUP BY
在内部似乎大多数时候 select 插入第一个插入的行,content
i select 来自 messages
table 是错误的,而从 conversation_messages
编辑的 message_id
select 是正确的。
知道如何在一次查询中执行此操作吗?如果您有任何更改 table 结构的建议,我也将不胜感激。
提前致谢。
这是可能的,因为您使用 AUTO_INCREMENT
意味着最高 ID 属于最新消息:
SELECT
messages.*,
FROM
conversations
INNER JOIN (
SELECT conversation_id, MAX(message_id) AS maxmsgid
FROM conversation_messages
GROUP BY conversation_id
) AS latest ON latest.conversation_id=conversations.id
INNER JOIN messages
ON messages.message_id=latest.maxmsgid
WHERE
1=1 -- whatever you want or need!
由于此查询肯定会很慢,您可能需要考虑几个选项:
- 投入硬件:使用足够的 RAM 并配置 MySQL 尽可能晚地进入磁盘 table
- 使用非规范化并在
messages
上使用 ON AFTER INSERT
触发器更新 conversation_messages
上的字段,该字段包含最新的消息 ID
您可能想试试这个版本:
SELECT c_m.message_id, m.content, c_m.`status`
FROM expedition_conversations e_c join
conversation_messages c_m
ON c_m.conversation_id = e_c.conversation_id INNER JOIN
messages m
ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1 AND
NOT EXISTS (SELECT 1
FROM conversation_messages cm2
WHERE cm2.conversation_id = c_m.conversation_id AND
cm2.timestamp > c_m.timestamp
)
为了性能,您需要 conversation_messages(conversation_id, timestamp)
上的索引。
试试这个小技巧:
SELECT c_m.message_id, m.content, c_m.status
FROM expedition_conversations e_c
JOIN (select * from (
select * from conversation_messages
order by message_id desc) x
group by conversation_id) c_m ON c_m.conversation_id = e_c.conversation_id
INNER JOIN messages m ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1
如果 mysql - 5.6.19 - 这将适用于您的版本,并且应该优于其他方法。
我有三个 table,我需要他们的不同数据。遗憾的是,我还需要能够提取最新的行。
这是我的 tables:
消息:我只是将消息的内容存储在一个table中,因为一个文本可以发送给多个用户
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| message_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| content | varchar(255) | NO | | 0 | |
+------------+------------------+------+-----+---------+----------------+
对话:这个table只是反映了两个用户之间的一次对话。
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| partner_id | int(10) unsigned | NO | MUL | NULL | |
| conversation_id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| expedition_id | int(11) | NO | | NULL | |
| active | tinyint(4) | NO | | 1 | |
+-----------------+------------------+------+-----+---------+----------------+
conversation_messages:table 存储有关实际消息交换的信息。
+-----------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+-------+
| message_id | int(11) unsigned | NO | PRI | NULL | |
| receiver_id | int(11) unsigned | NO | PRI | NULL | |
| conversation_id | int(11) unsigned | NO | MUL | NULL | |
| status | tinyint(4) | NO | | NULL | |
| timestamp | datetime | YES | | NULL | |
+-----------------+------------------+------+-----+---------+-------+
我现在想做的是 select 每个对话中的最新消息,并从该消息中获取内容。 (听起来很简单,但是并没有找到简单的解决方法)。我尝试的是以下内容:
SELECT max(c_m.message_id), m.content, c_m.`status`
FROM expedition_conversations e_c, conversation_messages c_m
INNER JOIN messages m ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1 AND (c_m.conversation_id = e_c.conversation_id)
GROUP BY c_m.conversation_id;
可悲的是,由于 GROUP BY
在内部似乎大多数时候 select 插入第一个插入的行,content
i select 来自 messages
table 是错误的,而从 conversation_messages
编辑的 message_id
select 是正确的。
知道如何在一次查询中执行此操作吗?如果您有任何更改 table 结构的建议,我也将不胜感激。
提前致谢。
这是可能的,因为您使用 AUTO_INCREMENT
意味着最高 ID 属于最新消息:
SELECT
messages.*,
FROM
conversations
INNER JOIN (
SELECT conversation_id, MAX(message_id) AS maxmsgid
FROM conversation_messages
GROUP BY conversation_id
) AS latest ON latest.conversation_id=conversations.id
INNER JOIN messages
ON messages.message_id=latest.maxmsgid
WHERE
1=1 -- whatever you want or need!
由于此查询肯定会很慢,您可能需要考虑几个选项:
- 投入硬件:使用足够的 RAM 并配置 MySQL 尽可能晚地进入磁盘 table
- 使用非规范化并在
messages
上使用ON AFTER INSERT
触发器更新conversation_messages
上的字段,该字段包含最新的消息 ID
您可能想试试这个版本:
SELECT c_m.message_id, m.content, c_m.`status`
FROM expedition_conversations e_c join
conversation_messages c_m
ON c_m.conversation_id = e_c.conversation_id INNER JOIN
messages m
ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1 AND
NOT EXISTS (SELECT 1
FROM conversation_messages cm2
WHERE cm2.conversation_id = c_m.conversation_id AND
cm2.timestamp > c_m.timestamp
)
为了性能,您需要 conversation_messages(conversation_id, timestamp)
上的索引。
试试这个小技巧:
SELECT c_m.message_id, m.content, c_m.status
FROM expedition_conversations e_c
JOIN (select * from (
select * from conversation_messages
order by message_id desc) x
group by conversation_id) c_m ON c_m.conversation_id = e_c.conversation_id
INNER JOIN messages m ON m.message_id = c_m.message_id
WHERE e_c.expedition_id = 1
如果 mysql - 5.6.19 - 这将适用于您的版本,并且应该优于其他方法。