表格如下所示:
id | number | provider| datetime | keyword|country|
1 | 1 | Mobitel |2012-11-05| JAM | RS |
2 | 2 | Telekom |2013-04-25| ASTRO| RS |
3 | 1 | Si.Mobil|2013-04-27| DOMACE| BA |
4 | 4 | Telenor |2013-04-21| BIP | HR |
5 | 7 | VIP |2013-04-18| WIN | CZ |
6 | 13 | VIP |2014-05-21| DOMACE| RS |
7 | 5 | VIP |2014-06-04| WIN | HU |
我需要在一次查询中对按关键字和国家/地区分组的所有数字求和,并再次对按关键字、国家/地区和提供商分组的所有数字求和。
我是这样尝试的:
SELECT (SELECT SUM(number),country, keyword
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword )
num_of_all_subs,
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
但是这个查询会抛出一个错误:
#1241 - Operand should contain 1 column(s)
这是我期望得到的:
id | num_of_all_subs|num_of_subs | provider| datetime | keyword|country|
1 | 19 | 4 | Mobitel |2012-11-05| JAM | RS |
2 | 12 | 5 |Telekom |2013-04-25| ASTRO| RS |
3 | 18 | 1 |Si.Mobil |2013-04-27| DOMACE| BA |
4 | 42 | 21 |Telenor |2013-04-21| BIP | HR |
5 | 76 | 23 |VIP |2013-04-18| WIN | CZ |
6 | 13 | 3 |VIP |2014-05-21| DOMACE| RS |
7 | 53 | 11 |VIP |2014-06-04| WIN | HU |
字段 num_of_all_subs
表示 JAM(关键字)和 RS(国家/地区)的所有数字之和为 19,但每个 Mobitel(提供商)为 num_of_subs
4 来自所有 19 个,因为该国家/地区和关键字还有其他提供程序(即使它们未显示在表架构中)。
请帮我提取这些数据,因为我卡住了。
最佳答案
num_of_all_subs
的子查询(它是一个数字)必须只返回一列,下一个问题返回一行。此外,此子查询将在您分组之前进行评估,而您实际上想要首先分组并获取列 num_of_subs
、country
、keyword
和 provider
,然后向第一个结果集添加另一列 num_of_all_subs
。
您可以完全按照刚刚描述的方式执行此操作:首先获取分组子查询(此处称为 details
),然后使用依赖子查询为该子查询中的每一行获取 的值>num_of_all_subs
通过查看表格(再次)并对具有相同 provider
和 country
的所有行求和:
SELECT
(SELECT SUM(number)
FROM daily_subscriptions ds
WHERE datetime >= '2016-02-01 23:59:59'
and ds.country = details.country
and ds.keyword = details.keyword
) as num_of_all_subs,
details.*
from
(select
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
) as details;
另一种方法是分别计算两组,一组包括 provider
(details
),另一组不包括(all_subs
)。一个将包含 num_of_subs
,一个将包含 num_of_all_subs
。当这两个查询具有相同的 country
和 keyword
时,您可以组合(join
):
SELECT
all_subs.num_of_all_subs,
details.*
from
(select
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
) as details
left join
(SELECT
SUM(number) as num_of_all_subs,
country,
keyword
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword
) as all_subs
on all_subs.keyword = details.keyword and all_subs.country = details.country;
在您的情况下,您可以使用 join
而不是 left join
,因为第一个子查询中的每一行都将在第二个子查询中有一行,尽管它是通常更安全的方法是保留它。
虽然理论上,MySQL 可以相同地执行这些查询(并且对于不太复杂的查询,它实际上会在可能和有用的情况下优化和处理依赖子查询,如连接),在当前的 MySQL 版本中,情况很可能不是这样第二个选项可能更快。无论如何,对于这两个版本,(country, keyword, provider)
上的复合索引都会产生奇迹。
关于mysql - 如何在外部查询和子查询中对同一个表进行不同的分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42341883/