mysql - 如何使用考虑两列的 GROUP BY?

标签 mysql sql

我在 MySQL 中有一个像这样的消息表。

   +--------------------+--------------+------+-----+---------------------+----------------+
    | Field              | Type         | Null | Key | Default             | Extra          |
    +--------------------+--------------+------+-----+---------------------+----------------+
    | id                 | int(11)      | NO   | PRI | NULL                | auto_increment |
    | subject            | varchar(120) | NO   |     | NULL                |                |
    | body               | longtext     | NO   |     | NULL                |                |
    | sent_at            | datetime     | YES  |     | NULL                |                |
    | recipient_read     | tinyint(1)   | NO   |     | 0                   |                |
    | recipient_id       | int(11)      | NO   | MUL | 0                   |                |
    | sender_id          | int(11)      | NO   | MUL | 0                   |                |
    | thread_id          | int(11)      | NO   | MUL | 0                   |                |
    +--------------------+--------------+------+-----+---------------------+----------------+

收件人收件箱中的邮件将按 thread_id 分组,如下所示:

SELECT * FROM message WHERE recipient_id=42  GROUP BY thread_id ORDER BY sent_at DESC

我的问题是如何考虑recipient_read,以便结果中的每一行也显示线程中最后一条消息的recipient_read值是什么?

最佳答案

在原始查询中,ORDER BY仅在GROUP BY之后满足手术。 ORDER BY影响返回行的顺序。它不影响返回哪些行。

对于 SELECT 列表中的非聚合表达式,无法确定将返回哪些值;每列的值将来自折叠组中的某些行。但不能保证它是第一行、最新行或任何其他特定行。 MySQL 的行为(允许查询运行而不抛出错误)是由 MySQL 扩展启用的。

其他关系数据库会在查询时抛出“SELECT 列表中非聚合而不是 GROUP BY”类型的错误。当 ONLY_FULL_GROUP_BY 时,MySQL 表现出类似的(标准)行为。包含在sql_mode中系统变量。由于非标准、MySQL 特定的扩展,MySQL 允许运行原始查询(并返回意外结果)。

原始查询的模式基本上被破坏了。

<小时/>

为了得到满足规范的结果集,我们可以编写一个查询来获取最新(最大)sent_at每个 thread_id 的日期时间,对于给定的一组recipient_id (在示例查询中,该集合是单个 recipient_id 。)

SELECT lm.recipient_id
     , lm.thread_id
     , MAX(lm.sent_at) AS latest_sent_at
  FROM message lm
 WHERE lm.recipient_id = 42
 GROUP
    BY lm.recipient_id
     , lm.thread_id

我们可以在另一个查询中使用该查询的结果,方法是创建一个内联 View (将其括在括号中,并在 FROM 子句(如表)中引用它,分配一个别名)。

我们可以将该结果集连接到原始表,以检索匹配行中的所有列。

像这样:

SELECT m.id
     , m.subject
     , m.body
     , m.sent_at
     , m.recipient_read
     , m.recipient_id
     , m.sender_id
     , m.thread_id
  FROM (
         SELECT lm.recipient_id
              , lm.thread_id
              , MAX(lm.sent_at) AS latest_sent_at
           FROM message lm
          WHERE lm.recipient_id = 42
          GROUP
             BY lm.recipient_id
              , lm.thread_id
       ) l
  JOIN message m
    ON m.recipient_id = l.recipient_id
   AND m.thread_id    = l.thread_id
   AND m.sent_at      = l.latest_sent_at
 ORDER
    BY ...

请注意,如果 (recipient_id,thread_id,sent_at)不保证是唯一的,可能会有多行具有相同的“最大值” sent_at ;也就是说,对于给定的最大值 sent_at,我们可以返回不止一行。 .

我们可以使用任何表达式对结果进行任意排序。这只会影响返回行的顺序,而不影响返回哪些行。

关于mysql - 如何使用考虑两列的 GROUP BY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59183692/

相关文章:

Mysql JOIN查询MAX值

sql - 在 latin1 中查询速度快,在 utf8 中查询速度慢 - 为什么?

sql - 在 SQL Server 中提取具有不一致属性和元素的嵌套 XML 数据

sql - 如何忽略数据库查询中重复的顺序值

sql - 将 NULL 数组填充到自定义聚合函数的最大长度

php - SQL 计算多列中的某些值

php - 分页和错误

mysql - 最佳性能索引结构

php - 将数组保存在数据库的一个字段中还是将每个值保存在单独的字段中?

php - mysql_num_rows 不起作用