MySQL:是否可以在同一结果表中显示汇总数据1和汇总数据2?

时间:2019-03-22 23:46:13

标签: mysql sql

假设我们有此表mytable

+--------+-------+-----+
| City   | User  | Amt |
+--------+-------+-----+
| London | John  | 100 |
| London | John  | 200 |
| London | James | 300 |
| London | James |  50 |
| Paris  | Jean  | 100 |
+--------+-------+-----+

我想编写一个查询,该查询将产生以下结果:

+--------+-------+------------+------------+
| City   | User  | AmtPerUser | AmtPerCity |
+--------+-------+------------+------------+
| London | John  |        300 |        650 |
| London | James |        350 |        650 |
| Paris  | Jean  |        100 |        100 |
+--------+-------+------------+------------+

这可以通过以下查询完成:

SELECT t1.City, User, AmtPerUser, AmtPerCity
FROM
    (SELECT City, User, SUM(Amt) as AmtPerUser FROM mytable GROUP BY City, User) t1
  JOIN
     (SELECT City, SUM(Amt) as AmtPerCity FROM mytable GROUP BY City ) t2
  USING (City);

但是此查询运行太慢,因为派生表没有索引。

所以我想知道是否有更有效的方法来完成此任务。

2019年3月25日更新

感谢您提供的解决方案。我目前仍在使用旧的MySQL 5.1。
很高兴了解MySQL 8中的窗口函数。

我已经在更大的集合上测试了查询(此处列出的数据已被复制3600次以形成18K行)。这是迄今为止最好的一个:

SELECT City, User, SUM(Amt) as AmtPerUser,
       SUM(SUM(Amt)) OVER (PARTITION BY City) as AmtPerCity
FROM mytable
GROUP BY City, User;

Demo on DB Fiddle

@GordonLinoff:43毫秒
我原来的查询:70ms
@GMB:135ms

事实证明,索引的存在或不存在无济于事。

3 个答案:

答案 0 :(得分:1)

在MySQL 8.0中,您可以将窗口函数与SELECT DISTINCT一起使用以获得相同的结果:

SELECT DISTINCT
    city, 
    user, 
    SUM(amt) OVER(PARTITION BY City, User) AmtPerUser,
    SUM(amt) OVER(PARTITION BY City) AmtPerCity
FROM mytable

Window函数通常比等效的聚合查询执行得更好。但是,如果您真的担心性能,那么您还是想创建索引(可能是(city, user)上的复合索引)。

Demo on DB Fiddle

| city   | user  | AmtPerUser | AmtPerCity |
| ------ | ----- | ---------- | ---------- |
| London | James | 350        | 650        |
| London | John  | 300        | 650        |
| Paris  | Jean  | 100        | 100        |

答案 1 :(得分:1)

使用窗口功能:

SELECT City, User, SUM(Amt) as AmtPerUser,
       SUM(SUM(Amt)) OVER (PARTITION BY City) as AmtPerCity
FROM mytable
GROUP BY City, User;

注意:这是基于MySQL 8 +。

在较早的版本中,带有JOIN和两个GROUP BY的版本可能是最好的方法。

答案 2 :(得分:0)

您可以使用GROUP BY ... WITH ROLLUP查询来获取输出数据中另一行的City总计(也包括总计行):

SELECT City, User, SUM(Amt)
FROM mytable
GROUP BY City, User WITH ROLLUP

输出:

City    User    SUM(Amt)
London  James   350
London  John    300
London  null    650
Paris   Jean    100
Paris   null    100
null    null    750

您可以通过ROLLUP值来识别NULL行-每个城市的总数具有City的城市名称和NULL的{​​{1}}的城市名称,而UserNULL的总计行都有City。尽管这并不是您要查找的格式,但是它会更有效。

Demo on dbfiddle