2017-09-05 170 views
-1

我有一个表,它包含从用户a到用户b(以及更多用户)的消息,反之亦然。具有不同行值的多列组

我想从用户之间的任何对话中检索最后一条消息,另外我想按消息时间降序排列。

我的表看起来像这样:

+--------+----------+--------------+------------------+ 
| userid | touserid | messsagetime |  message  | 
+--------+----------+---------------+------------------+ 
|  1 |  2 | 1504637613197 | hello   | 
|  1 |  2 | 1504637938942 | how are you?  | 
|  2 |  1 | 1504637970246 | i'm fine thanks. | 
|  3 |  1 | 1504640245930 | hello   | 
|  1 |  3 | 1504640322756 | hello!   | 
+--------+----------+---------------+------------------+ 

预期输出:

+--------+----------+---------------+------------------+ 
| userid | touserid | messsagetime |  message  | 
+--------+----------+---------------+------------------+ 
|  2 |  1 | 1504637970246 | i'm fine thanks. | 
|  1 |  3 | 1504640322756 | hello!   | 
+--------+----------+---------------+------------------+` 

不幸的是,我的MySQL知识是有限的,这是因为据我得到:

SELECT * 
    FROM 
    (SELECT * 
     FROM messages 
     WHERE userid = 1 
      or touserid = 1 
     ORDER 
      BY messagetime desc 
    ) AS a 
GROUP 
    BY userid 

哪个订购它的消息时间,只有1条消息from - to,但不会将来自其他用户的消息分组在一起。

为样本数据创建/插入:

CREATE TABLE IF NOT EXISTS `1` ( `id` int(11) NOT NULL 
AUTO_INCREMENT, `touser` int(11) NOT NULL, `fromuser` int(11) NOT 
NULL, `messagetime` bigint(20) NOT NULL, `message` text COLLATE 
utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB 
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=6 ; 


INSERT INTO `1` (`id`, `touser`, `fromuser`, `messagetime`, `message`) 
VALUES (1, 1, 2, 1504637613197, 'hello'), (2, 1, 2, 1504637938942, 
'how are you? '), (3, 2, 1, 1504637970246, 'i''m fine thanks.'), (4, 
3, 1, 1504640245930, 'hello'), (5, 1, 3, 1504640322756, 'hello!'); 

是否有任何MySQL的魔力,将实现什么,我想在这里做什么?

+0

提供创建和插入语句将有助于更快地为其中的某个人解决此问题 –

+0

从user1到user2的最后一条消息应该发生什么? – RiggsFolly

+0

@RiggsFolly它们不应该被返回,因为从user2到user1的消息已经在以后发送。 – user327685

回答

1

有可能以更快的方式,但是这是我的第一关: http://rextester.com/FCQU57469

我们使用工会切换touserid和fromuserId所以我们可以找出两个人之间的“对话”。然后,我们只需获取每个配对的最大时间戳。然后,我们将其加入到时间和用户ID在一个或另一个中的基础集。这部分可能会很慢。应该注意的是,如果用户A和B在不同的日期或年份进行对话......只有两者之间的最新内容才会被返回。

SELECT x.* 
FROM (SELECT max(messageTime) mmt, A, B 
     FROM (SELECT touser A, fromuser B, messageTime 
      FROM SO46062696 
      UNION ALL 
      SELECT fromuser A, touser B, messageTime 
      FROM SO46062696) Z 
     WHERE A < B 
     GROUP BY A,B 
    ) Y 
INNER JOIN SO46062696 x 
on Y.mmt = x.messagetime 
and Y.A in (x.touser, x.fromuser) 
and Y.B in (x.touser, x.fromuser) 

具有低于#的线条可能是把TOUSER = 1

  • 在Z子集必须有它的工会之前两个声明的地方。这对我来说是表现的理想场所,但我不确定它会给你后面的结果,因为它只看Touser1。
  • 但也许你的意思是FromUser = 1或touser = 1,在这种情况下,它可能是理想的,它需要放在集合Y的where子句中的联合之后。两者都在下面说明

这个例子:http://rextester.com/CFO21487显示,其中A < B and Z.a=1 它是什么,我认为你是后;用户标识1参与(来往或来自)的所有对话以及他们与唯一对方的最近对话。在这种情况下,请考虑下面的USERId,而不要使用from或reference。

SELECT x.* 
FROM (SELECT max(messageTime) mmt, A, B 
     FROM (SELECT touser A, fromuser B, messageTime 
      FROM SO46062696 
      #WHERE touser = 1 #Prefered1 
      UNION ALL 
      SELECT fromuser A, touser B, messageTime 
      FROM SO46062696 
      #WHERE touser=1 #Prefered1) Z 
     WHERE A < B 
     # and Z.A = 1 #added Less Optimal 
     GROUP BY A,B 
    ) Y 

INNER JOIN SO46062696 x 
on Y.mmt = x.messagetime 
and Y.A in (x.touser, x.fromuser) 
and Y.B in (x.touser, x.fromuser) 

可能还有更优化的方法;但我需要了解userID 1的含义,因为userID不是数据集中的列。

+0

谢谢你的努力。我不太确定'WHERE'语句在查询中的位置。比方说'userId ='1''? – user327685

+0

经过更新以提供Z子集内的两个地方是最好的,但它必须在两个选择上进行。还添加了一个rextester示例,以便您可以使用它。然而,这可能不会给你想要的结果我不确定你是什么意思的userID = 1,所以它可能会更好之后A xQbert

+0

注意我的别名可能是清洁器。我很匆忙,没有考虑好名字,你可能想重新考虑A,B,X,Y,Z和更清晰的名称。 – xQbert