GoogleSQL中按收入分位数分组企业 如何仅返回公司与分位段
报错原因及无额外子查询修复方案
你修改代码后报错的核心原因是:CASE判断逻辑中引用了Percentile50_Max、Percentile90_Max两个字段,这两个字段既不是聚合函数结果,也不在GROUP BY的分组字段列表中,不符合SQL的分组聚合语法规则。
不需要新增额外子查询,因为这两个分位值是CROSS JOIN得到的全局唯一固定值,只要用聚合函数(比如MAX/MIN,不影响计算结果)包裹即可,修改后的可运行代码如下:
SELECT company, CASE WHEN SUM(revenue) > MAX(Percentile90_Max) THEN "Top" WHEN SUM(revenue) >= MAX(Percentile50_Max) THEN "Middle" ELSE "Bottom" END as percentile_section FROM revenue_table CROSS JOIN (SELECT APPROX_QUANTILES(revenue,100)[offset(50)] As Percentile50_Max, APPROX_QUANTILES(revenue,100)[offset(90)] As Percentile90_Max FROM (SELECT company, SUM(revenue) as revenue FROM revenue_table GROUP BY 1 ) ) GROUP BY 1 ORDER BY SUM(revenue) DESC
效率相关说明
你当前使用的子查询+CROSS JOIN的方案已经属于最优方案之一,计算全局分位的核心开销(先聚合所有公司的总营收、再扫描计算分位数)是不可避免的。
子查询并不是唯一的最优方案,你也可以用窗口函数的写法实现,逻辑更简洁,GoogleSQL优化器会生成和原方案几乎一致的执行计划,效率没有本质差异:
WITH company_total_revenue AS ( -- 先聚合每个公司的总营收 SELECT company, SUM(revenue) AS total_revenue FROM revenue_table GROUP BY 1 ) SELECT company, CASE WHEN total_revenue > APPROX_QUANTILES(total_revenue,100) OVER()[offset(90)] THEN "Top" WHEN total_revenue >= APPROX_QUANTILES(total_revenue,100) OVER()[offset(50)] THEN "Middle" ELSE "Bottom" END AS percentile_section FROM company_total_revenue ORDER BY total_revenue DESC
内容的提问来源于stack exchange,提问作者lyk
相关产品推荐
相关产品推荐

