【问题标题】:MSYQL SELECT and group conversations by user and show last messageMYSQL SELECT 并按用户分组对话并显示最后一条消息
【发布时间】:2018-04-20 12:50:24
【问题描述】:

我有一个用户表和一个消息表。

在消息表(名为messaggi)中有msg_tomsg_from,它们的消息(msg_text)和msg_date(这是一个日期和时间)。

我正在努力实现以下目标:

  1. utenti 表中的所有用户

  2. 对于发送或接收消息的每个用户,应显示最后一个消息

  3. 向非自己的人隐藏消息(在本例中 id_utente 1 = self)。

这是我想出的,但我不断收到所有消息或双重用户,等等......

SELECT CONCAT(LEFT(u.fname, 1), LEFT(u.lname, 1)) AS iniziali,
       u.email,
       u.color,
       CONCAT(u.fname, " ", u.lname) AS full_name,
       MAX(m.msg_date) AS msg_date,
       m.msg_text
FROM utenti u
     INNER JOIN messaggi m ON m.msg_to = u.id_utente
WHERE m.msg_to = 1
GROUP BY m.msg_to,
         m.msg_from
UNION
SELECT CONCAT(LEFT(u2.fname, 1), LEFT(u2.lname, 1)) AS iniziali,
       u2.email,
       u2.color,
       CONCAT(u2.fname, " ", u2.lname) AS full_name,
       "",
       ""
FROM utenti u2
WHERE u2.id_utente NOT IN
(
    SELECT id_utente
    FROM utenti u
         INNER JOIN messaggi m ON m.msg_to = u.id_utente
    WHERE m.msg_to = 1
          AND u.id_utente = 1
    GROUP BY m.msg_to,
             m.msg_from
);

这是一个小提琴:

http://sqlfiddle.com/#!9/106319/1

我想要的输出应该是:

| iniziali |       email |  color |    full_name |            msg_date |       msg_text |
|----------|-------------|--------|--------------|---------------------|----------------|
|       BV |  456@me.com | (null) |   Bill Villa | 2018-04-20 12:29:20 | Msg 2 (1 to 2) |
|       MG |  789@me.com | (null) |    Max Gazze | 2018-04-09 14:59:39 | Msg 1 (3 to 1) |
|       JB |  101@me.com | (null) |    Jack Blue |                     |                |

在这种情况下,我是 id#1,我只能看到从我发送的消息和发送给我的消息,对于每个用户,我只能看到最后一个接收或发送的消息。像 WhatsApp、Facebook Messanger、Telegram 等...您会看到每个联系人的联系人和发送/接收的最后一条消息。

不显示与其他用户(即:用户 2 到用户 3)之间的消息。

如您所见,我在用户列表中看不到自己 (id#1),对于 Jack Blue,我只看到他的名字,没有消息,因为用户 1 和 4 从未发送过任何消息。所以我最终得到一个用户列表,对于每个用户,我都会看到最新的消息(发送或接收),而没有消息的地方,我只看到带有空 msg_textmsg_date 的用户

【问题讨论】:

  • 您能否详细说明第 3 点?听起来您想从自己那里获取最近收到的消息?也许你可以给出你的小提琴的预期输出?
  • @PerlPingu 好的,我确实添加了一些数据。 Tku
  • @PerlPingu 我还编辑了小提琴并添加了更多关于没有消息的用户的详细信息。
  • 啊,我想我在最后一次编辑关于没有消息的用户之前已经完成了

标签: mysql greatest-n-per-group


【解决方案1】:

这是我的尝试,我使用联合,第一部分适用于那些有来自/到 id 1 的消息的用户,第二部分适用于那些没有的用户。

SELECT CONCAT(LEFT(u.fname, 1), LEFT(u.lname, 1)) AS iniziali,
   u.email,
   u.color,
   CONCAT(u.fname, " ", u.lname) AS full_name,
   u.id_utente,
   m.msg_date,
   m.msg_text
FROM utenti u, messaggi m
WHERE (m.msg_to = u.id_utente OR m.msg_from = u.id_utente)
AND (m.msg_to = 1 and m.msg_from != 1 OR m.msg_to != 1 and m.msg_from = 1)
AND m.msg_date = (SELECT MAX(m2.msg_date) FROM messaggi m2 WHERE (m2.msg_to = u.id_utente AND m2.msg_from = 1) OR (m2.msg_from = u.id_utente AND m2.msg_to = 1))
UNION ALL
SELECT CONCAT(LEFT(u.fname, 1), LEFT(u.lname, 1)) AS iniziali,
   u.email,
   u.color,
   CONCAT(u.fname, " ", u.lname) AS full_name,
   u.id_utente,
   '',
   ''
FROM utenti u
WHERE NOT EXISTS (SELECT * FROM messaggi m WHERE (m.msg_to = u.id_utente AND m.msg_from = 1) OR (m.msg_from = u.id_utente AND m.msg_to = 1))
AND u.id_utente != 1
ORDER BY msg_date DESC

【讨论】:

  • 我看到你想要一个 ORDER BY,所以我添加了它。
【解决方案2】:

经过努力,我想即使您已经接受了答案,我也不妨发布此内容。此查询也将根据您提供的示例数据工作。我使用了一个变量来允许对不同的用户进行测试。

set @uid = 1;
select u1.id_utente as id,
    CONCAT(LEFT(u1.fname, 1), LEFT(u1.lname, 1)) AS iniziali,
    u1.email as email,
    u1.color as color,
    concat(u1.fname, ' ', u1.lname) as full_name, 
    m.msg_date as msg_date,
    m.msg_text as msg_text
from utenti u1
join utenti u2 
    on u1.id_utente != u2.id_utente and u2.id_utente = @uid
left join messaggi m
    on m.msg_to = u1.id_utente and m.msg_from = u2.id_utente or
       m.msg_to = u2.id_utente and m.msg_from = u1.id_utente
where m.msg_date = (select max(msg_date) 
                    from messaggi m2
                    where m2.msg_to = u1.id_utente and m2.msg_from = u2.id_utente or
                    m2.msg_to = u2.id_utente and m2.msg_from = u1.id_utente) or
      m.id_msg is null
group by u1.id_utente
order by msg_date desc

@uid = 1,输出为

id  iniziali    email       color   full_name       msg_date                msg_text
2   BV          456@me.com  (null)  Bill Villa      2018-04-20T12:29:20Z    Msg 2 (1 to 2)
3   MG          789@me.com  (null)  Max Gazze       2018-04-09T14:59:39Z    Msg 1 (3 to 1)
4   JB          101@me.com  (null)  Jack Blue       (null)                  (null)

@uid = 2,输出为

id  iniziali    email       color   full_name       msg_date                msg_text
1   JL          123@me.com  (null)  Joe Lombardi    2018-04-20T12:29:20Z    Msg 2 (1 to 2)
3   MG          789@me.com  (null)  Max Gazze       2018-04-09T15:03:44Z    Msg 1 (3 to 2)
4   JB          101@me.com  (null)  Jack Blue       (null)                  (null)

@uid = 3,输出为

id  iniziali    email       color   full_name       msg_date                msg_text
2   BV          456@me.com  (null)  Bill Villa      2018-04-09T15:03:44Z    Msg 1 (3 to 2)
1   JL          123@me.com  (null)  Joe Lombardi    2018-04-09T14:59:39Z    Msg 1 (3 to 1)
4   JB          101@me.com  (null)  Jack Blue       (null)                  (null)

@uid = 4,输出为

id  iniziali    email       color   full_name       msg_date                msg_text
1   JL          123@me.com  (null)  Joe Lombardi    (null)                  (null)
2   BV          456@me.com  (null)  Bill Villa      (null)                  (null)
3   MG          789@me.com  (null)  Max Gazze       (null)                  (null)

【讨论】:

    【解决方案3】:

    好的,所以我想我可能有一个解决方案。我已经用你的小提琴对其进行了测试,它似乎工作正常。

    通过结合 MySQL GROUP BY 行为(仅返回组中的第一个)和 ORDER BY,我们可以实现所需的结果,尽管最终结果是按名称排序的。 (编辑:只需将 ORDER BY msg_date desc 添加到 SQL 查询的末尾,即可改为按日期排序)

    编辑:我已将查询更改为在id_utente 上分组,并按msg_date 排序。它适用于正在运行的小提琴MySQL version 5.6

    SELECT * FROM ((SELECT CONCAT(LEFT(u.fname , 1), LEFT(u.lname , 1)) as iniziali, 
            u.id_utente,
            u.email, 
            u.color, 
            CONCAT(u.fname, " ", u.lname) as full_name, 
            m.msg_date,
            m.msg_text 
      FROM utenti u
      LEFT JOIN messaggi m ON m.msg_to = u.id_utente
      WHERE (m.msg_from = 1) OR m.msg_date is NULL)
      UNION
      (SELECT CONCAT(LEFT(u.fname , 1), LEFT(u.lname , 1)) as iniziali, 
            u.id_utente,
            u.email, 
            u.color, 
            CONCAT(u.fname, " ", u.lname) as full_name, 
            m.msg_date,
            m.msg_text 
      FROM utenti u
      LEFT JOIN messaggi m ON m.msg_from = u.id_utente
      WHERE (m.msg_to = 1) OR m.msg_date is NULL)
      ORDER BY id_utente, msg_date desc) st1
      WHERE id_utente != 1
      GROUP BY id_utente ORDER BY msg_date desc
    

    然后在你的小提琴中返回

    iniziali | id_utente |  email      | color  | full_name  | msg_date             | msg_text
    ---------+-----------+-------------+--------+------------+----------------------+-------------------
    BV       |         2 | 456@me.com  | (null) | Bill Villa | 2018-04-20T12:29:20Z | Msg 2 (1 to 2)
    MG       |         3 | 789@me.comm | (null) | Max Gazze  | 2018-04-09T14:59:39Z | Msg 1 (3 to 1)
    JB       |         4 | 101@me.comm | (null) | Jack Blue  | (null)               | (null)
    

    【讨论】:

    • 这太棒了,只有 3 件事,(1)它们按名称排序,应该按最后一条消息排序,最近在顶部(2)在我的真实数据库中我看到一切都很好,但第一个人有他的第一条消息而不是最后一条,其余的都可以(3)GROUP BY应该由用户ID(id_utente)完成,因为可以有2个人同名
    • ORDER BY msg_date desc更改顺序不起作用
    • 嗯,它在小提琴中运行良好。您可以将第一个人的行添加到小提琴中,以便我可以检查它不仅仅是与他们的数据有关吗?按 user_id 分组很容易解决
    猜你喜欢
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    相关资源
    最近更新 更多