按组排序“汇总”

时间:2009-11-20 05:39:39

标签: mysql sql

我发现group by使用的“with rollup”选项非常有用。但它不符合“order by”条款。 有没有办法按我想要的方式订购以及计算小计?

CREATE TABLE `mygroup` (
  `id` int(11) default NULL,
  `country` varchar(100) default NULL
) ENGINE=MyISAM ;

INSERT INTO `mygroup` VALUES (1,'India'),(5,'India'),(8,'India'),(18,'China'),(28,'China'),(28,'China');

mysql>select country, sum(id) from mygroup group by country with rollup; 
+---------+---------+
| country | sum(id) |
+---------+---------+
| China   |      74 | 
| India   |      14 | 
| NULL    |      88 | 
+---------+---------+
3 rows in set (0.00 sec)

mysql>select country, sum(id) as cnt from mygroup group by country order by cnt ;
+---------+------+
| country | cnt  |
+---------+------+
| India   |   14 | 
| China   |   74 | 
+---------+------+
2 rows in set (0.00 sec)

mysql>select country, sum(id) as cnt from mygroup group by country with rollup order by cnt;
ERROR 1221 (HY000): Incorrect usage of CUBE/ROLLUP and ORDER BY

Expected Result:
+---------+------+
| country | cnt  |
+---------+------+
| India   |   14 | 
| China   |   74 | 
| NULL    |   88 | 
+---------+---------+
3 rows in set (0.00 sec)

6 个答案:

答案 0 :(得分:12)

尝试使用临时表

 SELECT * 
 FROM 
 (
     SELECT country, sum(id) as cnt 
     FROM mygroup GROUP BY country WITH rollup
 ) t 
 ORDER BY cnt;

本文可以帮助您link text

答案 1 :(得分:10)

您是否尝试过将订单放入分组?

SELECT country, SUM(id) 
    FROM mygroup 
GROUP BY country DESC WITH ROLLUP;

应该返回:

+---------+---------+
| country | SUM(id) |
+---------+---------+
| India   |      14 |
| China   |      74 |
| NULL    |      88 |
+---------+---------+

http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html

答案 2 :(得分:3)

您可以尝试此查询:

 SELECT country,id
     FROM mygroup GROUP BY country ASC WITH ROLLUP

答案 3 :(得分:1)

解决方案

使用两个子查询,如下所示:

-- 3. Filter the redundant rows. Don't use HAVING; it produces a redundant row
--    when there's only one country.
SELECT r2.country, r2.cnt
FROM (
    -- 2. Save the ordering by giving each row an increasing serial number. 
    --    By grouping by serial numbers and country counts with rollup, the
    --    ordering is preserved and rollup data is calculated.
    SELECT (@s := @s + 1) AS sn, r1.country, SUM(r1.cnt) AS cnt
    FROM (
        -- 1. Calculate the country counts and order by them
        SELECT country, SUM(id) AS cnt
        FROM mygroup
        GROUP BY 1
        ORDER BY 2
    ) r1, (SELECT @s := 0) x
    GROUP BY 1, 2 WITH ROLLUP
) r2
WHERE r2.country IS NOT NULL OR r2.sn IS NULL

结果应按cnt排序,并在最后一行中使用小计:

+---------+------+
| country | cnt  |
+---------+------+
| India   |   14 | 
| China   |   74 | 
| NULL    |   88 | 
+---------+------+
3 rows in set (0.00 sec)

答案 4 :(得分:0)

两个子查询解决方案不必要地复杂。您只需要一个,而无需序列号。

select country, cnt
from (
    select
        country,
        sum(id) as cnt
    from mygroup
    group by country with rollup
) mygroup_with_rollup
order by country is null, cnt, country;

country is null将汇总行放在末尾。

答案 5 :(得分:0)

似乎since 2017 MySQL具有GROUPING()函数。使用ORDER BY时可以使用。此外,GROUP BY和ORDER BY现在可以共存(您原来的问题的第三个查询不再引发错误),但是在尝试对数据进行排序时确实存在一些缺陷,通常只是将ROLLUP引发到表的顶部当使用DESC时,我将演示其他问题,然后说明如何解决。让我们用扳手来处理原始数据:

INSERT INTO `mygroup` VALUES (-8,'Kenya'),(-12,'Kenya');

使用上面显示的临时表方法,将在表中间出现NULL / ROLLUP的地方得到这些结果,这是另一个问题,可能甚至比到达顶部更糟:

+---------+------+
| country | cnt  |
+---------+------+
| Kenya   |  -20 |
| India   |   14 |
| NULL    |   68 |
| China   |   74 |
+---------+------+

我们可能不希望这样,使用新的关键字GROUPING(),我们可以先按项目的分组对项目进行排序,然后在每个组中按单独的列进行排序:

-- big numbers on bottom, middle-numbered ROLLUP last
SELECT country, SUM(id) AS cnt FROM mygroup
GROUP BY country WITH ROLLUP ORDER BY GROUPING(country), cnt ASC;

-- big numbers on top, middle-numbered ROLLUP still last
SELECT country, SUM(id) AS cnt FROM mygroup
GROUP BY country WITH ROLLUP ORDER BY GROUPING(country), cnt DESC;

(DESC的)结果:

+---------+------+
| country | cnt  |
+---------+------+
| China   |   74 |
| India   |   14 |
| Kenya   |  -20 |
| NULL    |   68 |
+---------+------+

GROUPING()方法是一个更新的版本,可为您提供所需的内容,并具有确保将ROLLUP显示在所需位置的附加优点。