1

我有两张表,一张存储传入消息,另一张存储传出消息。我想要的是能够获得消息的对话视图,以便对来自/发往同一用户 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!!
4

4 回答 4

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 ;
于 2012-11-29T22:45:38.363 回答
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!! |

演示:http ://www.sqlfiddle.com/#!2/602c1/11

于 2012-11-29T22:45:37.743 回答
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

显然,从结果查询来看,如果 send_user_id 等于当前用户的 id,则为外发消息,否则为来自其他会话参与者之一的消息。

于 2012-11-29T22:50:39.597 回答
0

为什么要分开表?您可以将它们放在同一个表中并添加一列位类型的列,其中 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。这样,如果时间不是唯一的,您仍然可以确定顺序。

于 2012-11-29T22:49:53.353 回答