SQLite实现用户国家占比统计并合并低占比国家为OTHERS
嘿,这问题我熟!我来给你一步步解决,直接用SQL搞定所有需求,不用再靠PHP后端计算啦~
解决方案:用SQL直接生成按国家划分的占比列表(含OTHERS合并)
首先,我们可以用**CTE(公共表表达式)**来清晰地实现这个需求,几乎所有现代数据库(MySQL 8+、PostgreSQL、SQL Server等)都支持这种写法:
WITH total_users AS ( -- 先计算总订阅者数,避免重复计算 SELECT COUNT(*) AS total FROM SUBSCRIBERS ), country_stats AS ( -- 统计每个国家的用户数,并计算占比 SELECT s.Country, COUNT(*) AS population, -- 用100.0确保浮点除法,ROUND控制小数位数(这里保留1位,可按需调整) ROUND((COUNT(*) * 100.0 / tu.total), 1) AS percentage FROM SUBSCRIBERS s CROSS JOIN total_users tu GROUP BY s.Country, tu.total ) -- 最后合并占比低于1%的国家为OTHERS SELECT CASE WHEN percentage < 1 THEN 'OTHERS' ELSE Country END AS Country, SUM(population) AS Population, SUM(percentage) AS Percentage FROM country_stats GROUP BY CASE WHEN percentage < 1 THEN 'OTHERS' ELSE Country END ORDER BY Percentage DESC;
代码解释:
- total_users:先算出总用户数,这样后面计算占比时不用重复执行
COUNT(*),效率更高。 - country_stats:分组统计每个国家的用户数量,同时用
COUNT(*) * 100.0 / 总人数计算占比(100.0是关键,避免整数除法导致结果截断),用ROUND()控制百分比的小数位数。 - 最后一步:用
CASE WHEN把占比低于1%的国家替换为OTHERS,再重新分组求和,就能得到合并后的最终结果。
如果你的数据库不支持CTE(比如老版本MySQL):
可以改用子查询的写法,效果完全一样:
SELECT CASE WHEN percentage < 1 THEN 'OTHERS' ELSE Country END AS Country, SUM(population) AS Population, SUM(percentage) AS Percentage FROM ( SELECT s.Country, COUNT(*) AS population, ROUND((COUNT(*) * 100.0 / (SELECT COUNT(*) FROM SUBSCRIBERS)), 1) AS percentage FROM SUBSCRIBERS s GROUP BY s.Country ) AS country_stats GROUP BY CASE WHEN percentage < 1 THEN 'OTHERS' ELSE Country END ORDER BY Percentage DESC;
注意细节:
- 如果你想要整数百分比,把
ROUND(..., 1)改成ROUND(..., 0)即可。 - 若某个国家的占比刚好等于1%,会保留原国家名称;如果需要把等于1%的也归到OTHERS,把
percentage < 1改成percentage <= 1就行。 - 你的示例数据中UK和USA各2人,总人数4,占比都是50%,所以结果里不会出现OTHERS;如果有国家用户数少到占比低于1%,就会被合并进去。
内容的提问来源于stack exchange,提问作者Kenter
相关产品推荐
相关产品推荐

