我的表:
val
1
2
3
4
5
6
10
15
期望的结果:
bin | qty
1 | 1
2 | 2
4 | 3
8 | 3
这意味着有包容性/排他性范围
答案 0 :(得分:4)
在这种情况下,您的垃圾箱尺寸以对数字表示,为2。
如果您想使用其他纸盒尺寸,请在下面的脚本中替换2s。
select
pow(2, floor(ln(val) / ln(2))) as bin,
count(bin) as qty
from
mytable
group by
bin;
首先,我们在基数2中记录您的值。log(val, 2)
可能在某些RDBMS中有效,但如果没有,只需记住log(val, 2) = ln(val) / ln(2)
的日志属性。
val | ln(val) / ln(2)
1 | 0
2 | 1
3 | 1.58496250072
4 | 2
5 | 2.32192809489
然后我们这样做:
val | floor(ln(val) / ln(2))
1 | 0
2 | 1
3 | 1
4 | 2
5 | 2
最后,我们使用2的幂来将这些被覆盖的值转换为对数bin值。
val | pow(2, floor(ln(val) / ln(2)))
1 | 1
2 | 2
3 | 2
4 | 4
5 | 4
其余的只是按对数箱分组并计数。
如果您的RDBMS不支持pow(x, y)
,则可以使用exp(y * ln(x))
。然后表达式变为:
exp(floor(ln(val) / ln(2)) * ln(2))
log(0)未定义。在我测试的RDBMS中,它返回null。
如果你的表的值为0,你很可能想要将它们在0和1之间加之。为此,你可以用ifnull(...,0)包装整个表达式,如下所示:
ifnull(pow(2, floor(ln(val) / ln(2))), 0)
负数的对数是未定义的......但你可能想要将它们分类为[0到-1),[ - 1到-2],[ - 2到-4],[ - 4到-8 )等等。
如果您的数据库具有负值,则可以首先在值中使用abs
,然后通过将结果乘以val/abs(val)
来恢复原始信号,从而实现该分箱。然后你的表达成为:
pow(2, floor(ln(abs(val)) / ln(2))) * val/abs(val)
如果您的数据库同时包含负值和零值,则应将ifnull
包装在其他所有内容中。否则,val/abs(val)
部分将使您除以零,重新引入空值。
ifnull(pow(2, floor(ln(abs(val)) / ln(2))) * val/abs(val), 0)