按多个列分组,具有不同的行值

时间:2017-09-05 20:12:49

标签: mysql

我有一个表,其中包含从用户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

哪个按消息时间排序,只为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魔法可以实现我在这里尝试做的事情?

1 个答案:

答案 0 :(得分: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&#39; where子句中的联合之后。两者都说明如下。

此示例:http://rextester.com/CFO21487显示A < B and Z.a=1的位置 这是我认为你追求的; userId 1与(或来自)的所有对话及其最近的对话与唯一的合作伙伴。在这种情况下,将a视为下面的USERId,没有from或to 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不是数据集中的一列。