我有两个表,一个存储传入的消息,另一个存储传出的消息。我想要的是能够有一个消息的对话视图,以便来自/到同一用户ID的所有传入和传出消息被分组,并且对话按最新消息(进或出)排序
Outgoing
----------
user_id
time
message
Incoming
----------
user_id
time
message
我想要的是显示结果,例如
-> User A 9:10 pm Nice ...
<- User A 8:45 pm Our special is pepperoni!
-> User A 8:00 pm What's your special dish?
<- User B 9:00 pm We open at 5
-> User B 6:56 pm Hello What time to you open?
<- User C 8:43 pm Thanks!
-> User C 4:00 pm Loved the pizza today!!
知道如何编写查询来执行此操作吗?
修改
如果用户B然后重新输入文本,结果应为:
-> User B 9:15 pm Ok great!
<- User B 9:00 pm We open at 5
-> User B 6:56 pm Hello What time to you open?
-> User A 9:10 pm Nice ...
<- User A 8:45 pm Our special is pepperoni!
-> User A 8:00 pm What's your special dish?
<- User C 8:43 pm Thanks!
-> User C 4:00 pm Loved the pizza today!!
答案 0 :(得分:2)
您需要UNION
这两个表并相应地排序(ORDER BY
):
SELECT
'<-' AS direction, user_id, time, message
FROM
Outgoing
UNION ALL
SELECT
'->', user_id, time, message
FROM
Incoming
ORDER BY
user_id ASC,
time DESC ;
在复杂排序的附加说明之后:
SELECT
CASE WHEN m.d = 1 THEN '<-' ELSE '->' END AS direction,
m.user_id, m.time, m.message
FROM
( SELECT
u.user_id,
GREATEST( COALESCE(mo.time, mi.time),
COALESCE(mi.time, mo.time) ) AS maxtime
FROM
( SELECT user_id FROM Outgoing
UNION
SELECT user_id FROM Incoming
) AS u
LEFT JOIN
( SELECT user_id, MAX(time) AS time FROM Outgoing GROUP BY user_id
) AS mo
ON mo.user_id = u.user_id
LEFT JOIN
( SELECT user_id, MAX(time) AS time FROM Incoming GROUP BY user_id
) AS mi
ON mi.user_id = u.user_id
) AS b
JOIN
( SELECT 1 AS d, user_id, time, message FROM Outgoing
UNION ALL
SELECT 2 AS d, user_id, time, message FROM Incoming
) AS m
ON m.user_id = b.user_id
ORDER BY
b.maxtime ASC,
m.user_id ASC,
m.time DESC ;
答案 1 :(得分:1)
这样的事情应该按用户和时间得到结果。您需要在应用程序级别处理显示以显示每个用户的消息:
select * from (
select '->' as direction, o.* from outgoing o
union
select '<-' as direction, i.* from incoming i
) M
order by user_id asc, time desc
示例输出:
| DIRECTION | USER_ID | TIME | MESSAGE |
----------------------------------------------------------------------------------------
| -> | 1 | November, 29 2012 21:10:00+0000 | Nice ... |
| <- | 1 | November, 29 2012 20:45:00+0000 | Our special is pepperoni! |
| -> | 1 | November, 29 2012 20:00:00+0000 | What''s your special dish? |
| <- | 2 | November, 29 2012 21:00:00+0000 | We open at 5 |
| -> | 2 | November, 29 2012 18:56:00+0000 | Hello What time to you open? |
| <- | 3 | November, 29 2012 20:43:00+0000 | Thanks! |
| -> | 3 | November, 29 2012 16:00:00+0000 | Loved the pizza today!! |
答案 2 :(得分:1)
就个人而言,我并不喜欢你的桌子结构。对一个用户传入的消息是对另一个用户的传出消息,这意味着您需要复制每个表中系统中的每条消息。
我可能只有一个带有to和from字段的消息表。如果您有一个这样的表:
message_id (primary key)
from_user_id (indexed)
to_user_id (indexed)
message
time (indexed)
您的查询很简单:
SELECT *
FROM messages
WHERE from_user_id = ? OR to_user_id = ?
ORDER BY time DESC
请注意,这并不会为您显示的方式提供简单的查询(您需要进行一些查询后数据操作)。但它确实为您提供了最有效的查询查询,并防止您需要在存储中两次复制邮件。
如果你需要坚持分组对话的概念(甚至扩展到多方消息),那么也许你可以看看有一个对话表并修改你的模式是这样的:
对话(多对多联接表)
conversation_id (indexed)
user_id (indexed)
(compound primary key across both fields)
消息
message_id (primary key)
conversation_id (indexed)
sending_user_id
message
time (indexed)
使用像这样的查询
SELECT m.sending_user_id, m.message, m.time
FROM conversations AS c
INNER JOIN messages AS m ON c.conversation_id = m.conversation_id
WHERE c.user_id = ?
ORDER BY c.conversation_id, m.time DESC
显然,从结果查询中,如果sending_user_id等于当前用户的id,则它是传出消息,否则它是来自其他对话参与者的消息。
答案 3 :(得分:0)
为什么单独表?您可以将它们放在同一个表中,并添加一个类型为bit的列,其中1和0表示传入和传出。然后您的查询就像:
一样简单select user_id, time, message, inout from message order by user_id, time
对我来说,方向是告诉你一些关于消息的信息,无论哪种方式仍然是消息。
如果你仍然必须以另一种方式去做,那么你将不得不做一个联盟,但期望性能更差。您可以通过前台设计为您提供最佳性能调整。
with message as (
select user_id, time, message, 'incoming' from incoming
union all
select user_id, time, message, 'outgoing' from outgoing
) select * from message order by user_id, time
或类似的......
另外,你应该警惕按时间字段排序。根据经验,如果两条消息同时进入,您会发现意外结果。这很可能是因为您的示例只是细粒度到分钟,而不是秒或微秒。更好的方法是使用按升序自动分配的数字PK。这样,如果时间不是唯一的,你仍然有办法确定秩序。