获取每个线程的最后一条消息

时间:2014-09-07 14:12:25

标签: mysql sql greatest-n-per-group

SQL小提琴

http://sqlfiddle.com/#!2/1c5fc3/1

我正在尝试创建简单的邮件系统,但我遇到了SQL查询所需结果的问题。 这是我的桌子;我想获取INBOX数据..

INBOX Definiton解决了这个问题:

这应该是收件箱中的线程显示,即。谷歌邮件,但只显示该线程中的最后一条消息与原始创建线程的用户和最后一个在线程中回复的用户,如果最后一个用户是创建该线程的同一用户,并且beetween中没有回复消息不会在收件箱中显示出来。

TABLES:

THREAD
id_thread
id_last_message
id_user_inital
id_user_last

THREAD_USERS
id
id_thread
id_user

THREAD_MESSAGES
id_thread_messages
id_user_sender
id_thread
datetime
subject
body

MESSAGE_STATUS
id_messsage_status
id_thread_messages
id_user
status
datetime

我的逻辑是: 一旦发送了消息

THREAD 
id_thread  id_last_message  id_user_inital  id_user_last
1          1                1               1

THREAD_USERS 
id   id_thread   id_user
1    1           1
2    1           2

THEREAD_MESSAGES
id_thread_messages   id_user_sender   id_thread   datetime           subject   body
1                    1                1           07.09.2014 16:02   'title'   'text message'

MESSAGE_STATUS
id_message_status   id_thread_messages   id_user   status   datetime
1                   1                    1         4        07.09.2014 16:02
2                   1                    2         1        07.09.2014 16:02

让我们说状态可以是

0 = deleted (do not show at all)
1 = new (show only to user that is on the receiving end)
2 = read (this status will be shown to all users in the thread)
3 = replied (show only to user that makes this action)
4 = sent (show only to user that makes this action)

查询:

SELECT * 
   FROM thread
      JOIN thread_users
         ON thread.id_thread = thread_users.id_thread
      JOIN thread_messages 
         ON thread.id_thread = thread_messages.id_thread
         JOIN message_status 
            ON thread_messages.id_thread_messages = message_status.id_thread_messages
   WHERE 
          thread_users.id_user = 2
      AND message_status.status != 0
      AND message_status.status != 4
      AND thread.id_user_last != message_status.id_user

示例数据

主题

id_thread   id_last_message   id_user_inital  id_user_last
1           4                 1               2
2           2                 3               3
3           3                 4               4

THREAD_USERS

id   id_thread   id_user
1    1           1
2    1           2
3    2           3
4    2           2
5    3           4
6    3           2

THEREAD_MESSAGES

id_thread_messages   id_user_sender   id_thread   datetime          subject     body
1                    1                1           07.09.2014 16:02  'title'     'text message'
2                    3                2           07.09.2014 16:05  'hey two'   'foo'
3                    4                2           07.09.2014 16:07  'hey two'   'bar' 
4                    2                1           07.09.2014 16:10  'title'     'replay on 1st'

MESSAGE_STATUS

id_message_status  id_thread_messages  id_user   status   datetime
1                  1                   1         4        07.09.2014 16:02 
2                  1                   2         1        07.09.2014 16:02
3                  2                   3         4        07.09.2014 16:05 
4                  2                   2         1        07.09.2014 16:05  
5                  3                   4         4        07.09.2014 16:07
6                  3                   2         1        07.09.2014 16:07  
7                  4                   2         4        07.09.2014 16:10 
8                  4                   1         1        07.09.2014 16:10

你如何从这种情况中提取INBOX数据,因为我在圈子里旋转几个小时并且不能完全弄清楚我做错了什么。

谢谢。

3 个答案:

答案 0 :(得分:1)

我认为这是您正在寻找的解决方案

SELECT * FROM thread
JOIN  thread_users ON thread.id_thread = thread_users.id_thread
JOIN thread_messages ON thread.id_thread = thread_messages.id_thread
JOIN message_status ON thread_messages.id_thread_messages = message_status.id_thread_messages
WHERE thread_users.id_user = 2
AND thread_users.id_user = message_status.id_user
AND message_status.status != 0
AND message_status.status != 4
AND thread.id_user_last != message_status.id_user

答案 1 :(得分:1)

考虑到消息状态的说明后更新了解决方案:

SELECT DISTINCT t.*, tm.* , ms.*
FROM thread t 
   -- tm should be last message
   INNER JOIN thread_messages tm ON t.id_thread = tm.id_thread
      INNER JOIN message_status ms ON (ms.id_thread_messages = tm.id_thread_messages)AND
                                      (ms.id_user=2)AND
                                      (ms.status!=0)
   -- try to find message after tm, and then in WHERE filter only those cases where there is no message after tm
   LEFT JOIN thread_messages tm_next 
        INNER JOIN message_status ms_next ON (ms_next.id_thread_messages = tm_next.id_thread_messages)AND
                                             (ms_next.id_user=2)AND
                                             (ms_next.status!=0)
      ON (t.id_thread = tm_next.id_thread)and
         (tm_next.datetime>tm.datetime)

   LEFT JOIN thread_messages tm_other 
        INNER JOIN message_status ms_other ON (ms_other.id_thread_messages = tm_other.id_thread_messages)AND
                                             (ms_other.id_user=2)AND
                                             (ms_other.status!=0)
      ON (t.id_thread = tm_other.id_thread)and
         (tm_other.id_thread_messages!=tm.id_thread_messages)and
         (tm_other.id_user_sender!=2)

WHERE 
  -- ensure tm is last message in thread
  (tm_next.id_thread is null)and
  (
       -- there is a non deleted message from another user in current thread
       (tm_other.id_thread_messages is not null)or

       -- last message is not from current user
       (tm.id_user_sender!=2)
  )

SqlFiddle是here。 让我知道这对你有用。

答案 2 :(得分:0)

现在有了INBOX的含义的描述,我建议你在查询中严重依赖EXISTS子句。以下是它的外观示例:

SELECT * 
FROM thread t INNER JOIN 
  thread_messages tm ON t.id_thread = tm.id_thread
WHERE
 EXISTS ( -- User is in the thread.
   SELECT * FROM thread_users tu 
   WHERE t.id_thread = tu.id_thread AND tu.id_user = 2
 )
 AND NOT EXISTS ( -- Exclude earlier messages for thread.
   SELECT * FROM thread_messages  WHERE 
   tm.id_thread = id_thread AND datetime > tm.datetime
   AND EXISTS (-- Exclude deleted messages here
     SELECT * FROM message_status 
     WHERE thread_messages.id_thread_messages = id_thread_messages
       AND status != 0
       AND status != 4
   )
 )
 AND EXISTS ( -- Include messages that were not deleted or send to self.
    SELECT * FROM message_status 
    WHERE tm.id_thread_messages = id_thread_messages
     AND status != 0
     AND status != 4
     AND t.id_user_last != id_user -- not sure what is this for
 )
 AND EXISTS ( -- Include threads with messages from several users
   SELECT * FROM thread_messages 
   WHERE tm.id_thread = id_thread 
     AND tm.id_user_sender != t.id_user_inital)

http://sqlfiddle.com/#!2/1c5fc3/39