MySQL 中的 GROUP BY 中断 ORDER BY 列表

Posted

技术标签:

【中文标题】MySQL 中的 GROUP BY 中断 ORDER BY 列表【英文标题】:GROUP BY in MySQL break ORDER BY list 【发布时间】:2013-06-07 11:24:07 【问题描述】:

我有这个 SQL:

SELECT
    c.name AS category_name,
    a.name,
    a.path,
    a.extension,
    a.width,
    a.height,
    a.server
FROM categories c
JOIN news_categories nc ON nc.categories_id = c.id
JOIN news_attachments na ON nc.news_id = na.news_id
JOIN attachments a ON na.attachments_id = a.id
WHERE na.cover = 1
ORDER BY nc.news_id DESC

它显示了一个正确的结果

+---------------+------------+---------------------+-----------+-------+--------+--------+
| category_name | name       | path                | extension | width | height | server |
+---------------+------------+---------------------+-----------+-------+--------+--------+
| Игры          | c54950f283 | a6f00bcd/b25/cfaf2e | jpg       |   450 |    416 |      1 |
| Игры          | fa4249e534 | a6f00bcd/b89/cfaf2e | jpg       |   400 |    250 |      1 |
| Игры          | d7b009eeb7 | a6f00bcd/bfa/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 143cb7a38d | a6f00bcd/baa/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | a70451eca7 | a6f00bcd/bc6/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 3ab8a0c051 | a6f00bcd/b5b/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 206255a07a | a6f00bcd/b98/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 86ef53ee1f | a6f00bcd/b93/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | a50367f861 | a6f00bcd/b32/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | dcfdd990c6 | a6f00bcd/b32/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 5a3df9f4ad | a6f00bcd/b34/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | fb3ba0390d | a6f00bcd/b35/cfaf2e | jpg       |   200 |    140 |      1 |
| Игры          | 0e31ef118d | a6f00bcd/be5/cfaf2e | jpg       |   457 |    249 |      1 |
| Игры          | 82d41d9d62 | a6f00bcd/b97/cfaf2e | jpg       |   457 |    249 |      1 |
+---------------+------------+---------------------+-----------+-------+--------+--------+

但是如果我们添加GROUP BY,那么它会显示没有顺序的结果

SELECT
    c.name AS category_name,
    a.name,
    a.path,
    a.extension,
    a.width,
    a.height,
    a.server
FROM categories c
JOIN news_categories nc ON nc.categories_id = c.id
JOIN news_attachments na ON nc.news_id = na.news_id
JOIN attachments a ON na.attachments_id = a.id
WHERE na.cover = 1
GROUP BY c.id ORDER BY nc.news_id DESC

那么结果会是

+---------------+------------+---------------------+-----------+-------+--------+--------+
| category_name | name       | path                | extension | width | height | server |
+---------------+------------+---------------------+-----------+-------+--------+--------+
| Игры          | 82d41d9d62 | a6f00bcd/b97/cfaf2e | jpg       |   457 |    249 |      1 |
+---------------+------------+---------------------+-----------+-------+--------+--------+

但一定是这样的

+---------------+------------+---------------------+-----------+-------+--------+--------+
| category_name | name       | path                | extension | width | height | server |
+---------------+------------+---------------------+-----------+-------+--------+--------+
| Игры          | c54950f283 | a6f00bcd/b25/cfaf2e | jpg       |   450 |    416 |      1 |
+---------------+------------+---------------------+-----------+-------+--------+--------+

哪里出错了?

【问题讨论】:

您错误地使用了group by,其他所有 DBMS 都会拒绝您的查询。阅读此rpbouman.blogspot.de/2007/05/debunking-group-by-myths.html 和此mysqlperformanceblog.com/2006/09/06/… 了解更多信息。 @user2058653 GROUP BY 子句的意义何在? 每个类别 id 只需要一个结果 【参考方案1】:

GROUP BY 将您的记录分组到 c.id。因此,对于每个 c.id 值,您只会得到一行。

碰巧的是,您的查询中有多个该值的行,MySQL 将选择并显示单行:这里的最后一行。

对于所需的输出,请使用LIMIT 1

如果您希望结果集中有多个 c.id 值(类别),则必须提供定位 first 行的平均值,通常是主键。

SELECT *
FROM Table;

+---------------+------------+----------+
| pk            | category   | data     |
+---------------+------------+----------+
| 1             | red        | a        |
| 2             | red        | b        |
| 3             | red        | c        |
| 4             | red        | d        |
| 5             | red        | e        |
| 6             | red        | f        |
| 7             | green      | g        |
| 8             | green      | h        |
| 9             | green      | i        |
| 10            | green      | j        |
| 11            | blue       | k        |
| 12            | blue       | l        |
| 13            | blue       | m        |
| 14            | orange     | n        |
+---------------+------------+----------+

SELECT *
FROM Table
GROUP BY category;

+---------------+------------+----------+
| pk            | category   | data     |
+---------------+------------+----------+
| 1             | red        | a        |
| 7             | green      | g        |
| 11            | blue       | k        |
| 14            | orange     | n        |
+---------------+------------+----------+

SELECT *
FROM Table t
WHERE pk = (SELECT MAX(pk)
            FROM Table u
            WHERE u.category = t.category);

+---------------+------------+----------+
| pk            | category   | data     |
+---------------+------------+----------+
| 6             | red        | f        |
| 10            | green      | j        |
| 13            | blue       | m        |
| 14            | orange     | n        |
+---------------+------------+----------+

Another nice way of doing it

【讨论】:

每个类别我只需要一个结果idLIMIT 只会显示一个结果,但类别可以是(视频、游戏、软件),我需要为每个类别 ID 提供一个图像包含此类别的最新消息。 请参考我最后一句。 你能举个例子吗?

以上是关于MySQL 中的 GROUP BY 中断 ORDER BY 列表的主要内容,如果未能解决你的问题,请参考以下文章

mysql 可以group by 两个字段吗

使用 MySQL 通过 JOIN 获取 GROUP BY 中的 SUM

mysql中group by里面的问题

如何使用 GROUP BY 连接 MySQL 中的字符串?

MySQL 中的 GROUP BY 使用通配符

Django Average 和 Group By 中的 MYSQL 等效查询