假设我们有此表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;
@GordonLinoff:43毫秒
我原来的查询:70ms
@GMB:135ms
事实证明,索引的存在或不存在无济于事。
答案 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)
上的复合索引)。
| 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}}的城市名称,而User
和NULL
的总计行都有City
。尽管这并不是您要查找的格式,但是它会更有效。