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 列表的主要内容,如果未能解决你的问题,请参考以下文章