如何在外部查询和子查询

时间:2017-02-20 10:19:17

标签: mysql

表格如下:

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 - 操作数应包含1列

这是我期望得到的:

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,因为有该国家/地区和关键字的其他提供商(即使它们未显示在表架构中)。

请帮我提取这些数据,因为我被卡住了。

1 个答案:

答案 0 :(得分:1)

num_of_all_subs的子查询(单个数字)必须只返回一列,下一个问题是一行。此外,在您进行分组之前,将对此子查询进行评估,而您实际上希望首先分组并获取列num_of_subscountrykeywordprovider,之后,将另一列num_of_all_subs添加到第一个结果集。

您可以完全按照上述描述执行此操作:首先获取分组子查询(此处称为details),然后使用从属子查询为该子查询中的每一行获取num_of_all_subs的值通过查看表格(再次)并总结具有相同providercountry的所有行:

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;

另一种方法是单独计算两个组,一个包括providerdetails),一个没有(all_subs)。一个将包含num_of_subs,其中一个将包含num_of_all_subs。当这两个查询具有相同的joincountry时,您可以合并(keyword):

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)上的复合索引都会产生奇迹。