【问题标题】:How to group by rows but with the most recent date?如何按行分组但使用最近的日期?
【发布时间】:2013-08-22 03:22:18
【问题描述】:

在我的 MySQL 数据库中,我有一个这样的表,用于存储来自任何人的对话消息

id               int(11)           id of the message    
from member_id   int(11)           id of the person the message was sent from
to member_id     int(11)           id of the person the message was sent to 
date sent        datetime          date of when it was sent 
active           tinyint(1)        if the message is deleted    
text             longtext          the text of the message
from_read        tinyint(1)        boolean to know if the person who sent it read it 
to_read          tinyint(1)        boolean to know if the person who it got sent to read it

例如,它可能是这样的:

from_member_id to_member_id date sent
1              2            june 12
1              3            june 13
2              3            june 14
3              1            june 9

所以我们在121323之间进行了对话。

我正在尝试获取一个 select 语句,它将从用户参与的每个对话中为我提供当前用户参与的最新消息。因此,如果 1 已登录,那么我希望得到 2 行.结果集中的第一行将是上面的第二行(7 月 13 日),因为它是最新的,然后结果集中的第二行将是上面的第一行(6 月 12 日),这是来自 @ 的最新987654330@的两次对话。结果集还需要按发送日期排序,因此较新的对话列在顶部。

我正在尝试做的就像在安卓手机中发短信一样,您可以在其中看到对话列表以及每个列表中的最新消息。

这是我的 sql 查询

SELECT *
FROM (
    SELECT   *
    FROM     message
    WHERE `from member_id`=1 OR `to member_id`=1
    ORDER BY IF(`from member_id`=1, `to member_id`, `from member_id`)
) as t
GROUP BY IF(`from member_id`=1, `to member_id`, `from member_id`)

我只是将1 硬编码为当前用户。我正在做的是,按我可以使用 if 语句检查的另一个人的 id 对它们进行排序,然后对该结果进行分组,以便我尝试从每个对话中获取最近的一个。

问题是分组时,每个组可以有超过 1 行,它似乎只是随机选择一些行。如何让它选择具有最近发送日期值的行?

【问题讨论】:

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


    【解决方案1】:

    你在寻找这样的东西吗?

    SELECT m.*
      FROM message m JOIN
    (
      SELECT from_member_id, to_member_id, MAX(date_sent) date_sent
        FROM message
       WHERE from_member_id = 1
       GROUP BY from_member_id, to_member_id
    ) q
        ON m.from_member_id = q.from_member_id
       AND m.to_member_id = q.to_member_id
       AND m.date_sent = q.date_sent
     ORDER BY date_sent DESC
    

    样本输出:

    | FROM_MEMBER_ID | TO_MEMBER_ID | DATE_SENT | ---------------------------------------------- | 1 | 3 | 2013-06-13 | | 1 | 2 | 2013-06-12 |

    这里是SQLFiddle演示

    更新

    SELECT m.*
      FROM message m JOIN
    (
      SELECT LEAST(from_member_id, to_member_id) least_id, 
             GREATEST(from_member_id, to_member_id) greatest_id, 
             MAX(date_sent) date_sent
        FROM message
       WHERE from_member_id = 1 
          OR to_member_id   = 1
       GROUP BY    LEAST(from_member_id, to_member_id),
                GREATEST(from_member_id, to_member_id)
    ) q
        ON LEAST(m.from_member_id, m.to_member_id) = q.least_id
       AND GREATEST(m.from_member_id, m.to_member_id) = q.greatest_id
       AND m.date_sent = q.date_sent
     ORDER BY date_sent DESC
    

    样本输出:

    | FROM_MEMBER_ID | TO_MEMBER_ID | DATE_SENT | ---------------------------------------------- | 3 | 1 | 2013-06-14 | | 1 | 2 | 2013-06-12 |

    这里是SQLFiddle演示

    【讨论】:

    • 当最新消息来自当前用户时,此功能有效。但它不考虑从其他用户发送给当前用户的消息。
    • @omega 到底有没有帮助?
    • 我最终使用一种称为 groupwise maximum 的技术让它工作。 stackoverflow.com/questions/15211479/groupwise-maximum
    【解决方案2】:
    SELECT
      *
    FROM message m INNER JOIN
      (
        SELECT
          from_menber_id,
          MAX(date_sent) AS sentdate
        FROM message s
        GROUP BY from_menber_id
      ) AS a
        ON m.date_sent = a.sentdate AND a.from_menber_id = m.from_menber_id
    

    【讨论】:

    • 抱歉,这是表的名称。我已经编辑过了。请看看这是不是你需要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 2012-03-01
    • 2018-01-30
    相关资源
    最近更新 更多