MySQL数据库中,有一个包含单个数值列的表.我想将这些值的分布绘制为具有以下要求的条形图/直方图:

>图表中最多应有N个柱(间隔)

>每个条的宽度(x轴范围)应该是均匀的,每个条的高度应该反映此间隔中的值的数量.

>栏的端点应以圆数出现.我理解这是一个相当模糊的要求,但希望下面的例子将说明我的意思

>间隔应该是连续的,例如下一个间隔应该从前一个间隔开始

>理想情况下,应该可以使用单个查询检索数据

>可以使计数(y轴值)为0的间隔

>如果第一个间隔的下限小于最小值和/或最后一个间隔的上限大于最大值,则可以

如果N = 3且表包含以下数据

+------------+
| value |
+------------+
| -49.2 |
| -28.2 |
| 13.3 |
| 23.3 |
| 51.4 |
| 77.9 |
+------------+

在检查时,很容易看到间隔{-50..0,0..50,50..100}满足该数据集的要求和N的值.

但是,我正在努力想出一个适用于N和任何数据集的任何值的通用解决方案.这是我到目前为止所尝试的:

计算间隔宽度

通过以下查询获取最大值和最小值

SELECT min(value), max(value), count(*) FROM my_table
然后将结果传递给此(Groovy / Java)方法以计算每个间隔的宽度
// intervalCount is what I've referred to as "N"
static Integer getRoundedIntervalSize(Double min, Double max, Integer intervalCount) {
Number intervalSize = Math.ceil((max - min) / intervalCount)
Integer roundingScale = Math.log10(intervalSize) - 1
Number roundNearest = 10 ** roundingScale
// round up the interval size to the nearest roundNearest
Number intervalDelta = roundNearest - (intervalSize % roundNearest)
intervalSize + intervalDelta
}

获取频率分布

然后我使用以下查询(getRoundedIntervalSize返回的值替换为:groupSize)来获取每个区间中的值的数量

SELECT floor(value / :groupSize) * :groupSize as groupLowerLimit,
count(*) as groupCount
FROM my_table
GROUP BY groupLowerLimit
ORDER BY groupLowerLimit ASC

这将返回每个间隔的下限和每个间隔中的值的数量,这是构建频率分布所需的全部内容.

缺点

虽然这种方法在数据集相对均匀分布时工作得相当好,但在不是这种情况时,会产生宽度不同或不连续的区间.而且,当数据集的范围很小(例如,所有值在1和4之间)和N很大(例如30)时,产生的间隔的数量往往远小于N.

有没有更好的方法来解决满足上述要求的问题?