MySQL中如何为数据分桶生成直方图(替代width_bucket)
MySQL实现width_bucket等宽分桶、生成直方图的方案
MySQL没有原生内置的width_bucket等宽分桶函数,可通过以下两种方案实现完全一致的分桶效果,满足直方图统计需求:
- 通用算术计算方案(支持所有MySQL版本)
直接通过边界判断+数学计算实现分桶逻辑,不需要额外创建对象,和PostgreSQL、Oracle的width_bucket返回规则完全对齐:值小于最小值返回0,大于等于最大值返回桶数+1,区间内按等宽区间返回1~N的桶号。
对应示例SQL如下(和给出的PG/Oracle语法逻辑完全等价,将薪资在0~150000区间分为10个等宽桶):
上述逻辑里单个桶的宽度为15000,014999落在1号桶、1500029999落在2号桶,以此类推135000~149999落在10号桶。如果需要直接生成直方图统计结果,只需要按分桶字段做SELECT department_id, last_name, salary, CASE WHEN salary < 0 THEN 0 WHEN salary >= 150000 THEN 11 ELSE FLOOR(salary / (150000/10)) + 1 END AS salary_bucket FROM employees;GROUP BY聚合计数即可。 - 自定义函数方案(一劳永逸复用原生语法)
如果需要频繁使用分桶逻辑,可以在MySQL中创建自定义的width_bucket函数,之后直接和PG、Oracle一样调用即可:
函数创建完成后,原来在PG/Oracle中写的SQL不需要做任何修改,就可以直接在MySQL中执行:DELIMITER // CREATE FUNCTION width_bucket( expr DECIMAL(20,4), min_val DECIMAL(20,4), max_val DECIMAL(20,4), bucket_count INT ) RETURNS INT DETERMINISTIC BEGIN DECLARE bucket_width DECIMAL(20,4); IF expr < min_val THEN RETURN 0; ELSEIF expr >= max_val THEN RETURN bucket_count + 1; END IF; SET bucket_width = (max_val - min_val) / bucket_count; RETURN FLOOR((expr - min_val)/bucket_width) + 1; END // DELIMITER ;select department_id, last_name, salary, width_bucket(salary,0,150000,10) from employees;
注意:MySQL 8.0提供的
NTILE()窗口函数是按记录行数均分的等频分桶,不是width_bucket对应的按数值区间均分的等宽分桶,二者逻辑差异很大,不要混用。
内容的提问来源于stack exchange,提问作者Anna Quoc Nguyen
相关产品推荐
相关产品推荐

