题
有没有在MySQL中指定的块大小的方法吗?现在,我想下面的SQL查询:
select total, count(total) from faults GROUP BY total;
正在被产生的数据是不够好,但有太多的行数。我需要的是一种方式对数据进行分组到预定义的垃圾箱。我可以从一个脚本语言做到这一点,但有没有办法直接在SQL办呢?
示例:
+-------+--------------+
| total | count(total) |
+-------+--------------+
| 30 | 1 |
| 31 | 2 |
| 33 | 1 |
| 34 | 3 |
| 35 | 2 |
| 36 | 6 |
| 37 | 3 |
| 38 | 2 |
| 41 | 1 |
| 42 | 5 |
| 43 | 1 |
| 44 | 7 |
| 45 | 4 |
| 46 | 3 |
| 47 | 2 |
| 49 | 3 |
| 50 | 2 |
| 51 | 3 |
| 52 | 4 |
| 53 | 2 |
| 54 | 1 |
| 55 | 3 |
| 56 | 4 |
| 57 | 4 |
| 58 | 2 |
| 59 | 2 |
| 60 | 4 |
| 61 | 1 |
| 63 | 2 |
| 64 | 5 |
| 65 | 2 |
| 66 | 3 |
| 67 | 5 |
| 68 | 5 |
------------------------
什么我要找:
+------------+---------------+
| total | count(total) |
+------------+---------------+
| 30 - 40 | 23 |
| 40 - 50 | 15 |
| 50 - 60 | 51 |
| 60 - 70 | 45 |
------------------------------
我想这不能以直接的方式来实现,但是对任何相关的存储的过程的参考将被罚款,以及
解决方案
这是一个关于一个超快速和肮脏的方式来创建直方图后 在MySQL为数字值。
有多种其他的方法来创造更好的柱状图和 更灵活,使用CASE语句和其他类型的复杂逻辑。 这种方法赢了我一次又一次,因为它只是那么容易 修改为每个用例,所以简明扼要。你这是怎么 做到这一点:
SELECT ROUND(numeric_value, -2) AS bucket, COUNT(*) AS COUNT, RPAD('', LN(COUNT(*)), '*') AS bar FROM my_table GROUP BY bucket;
只要改变numeric_value到无论你的列,变更 舍入增量,仅此而已。我做了酒吧在 对数刻度,让他们不长,当你有太多的 大值。
numeric_value应在舍入运算偏移,基于所述舍入增量,以便确保所述第一桶包含一样多的元素下面桶。
e.g。与ROUND(numeric_value,-1),在numeric_value范围[0,4](5种元素)将被放置在第一桶,而[5,14](10种元素)的第二,第三[15,24],除非numeric_value经由ROUND适当地偏移(numeric_value - 5,-1)。
这是看起来相当一些随机数据这样的查询的示例 甜。好足够的数据的快速评价。
+--------+----------+-----------------+ | bucket | count | bar | +--------+----------+-----------------+ | -500 | 1 | | | -400 | 2 | * | | -300 | 2 | * | | -200 | 9 | ** | | -100 | 52 | **** | | 0 | 5310766 | *************** | | 100 | 20779 | ********** | | 200 | 1865 | ******** | | 300 | 527 | ****** | | 400 | 170 | ***** | | 500 | 79 | **** | | 600 | 63 | **** | | 700 | 35 | **** | | 800 | 14 | *** | | 900 | 15 | *** | | 1000 | 6 | ** | | 1100 | 7 | ** | | 1200 | 8 | ** | | 1300 | 5 | ** | | 1400 | 2 | * | | 1500 | 4 | * | +--------+----------+-----------------+
一些注意事项:有没有匹配将不会出现在计数范围 - 你会不会在数列中的零。另外,我使用的 这里ROUND函数。你可以很容易地与TRUNCATE更换 如果你觉得它更有意义给你。
我发现它在这里 http://blog.shlomoid.com /2011/08/how-to-quickly-create-histogram-in.html
其他提示
麦克DelGaudio的回答是我做到这一点,但有轻微的变化:
select floor(mycol/10)*10 as bin_floor, count(*)
from mytable
group by 1
order by 1
优点?您可以在垃圾箱一样大或只要你想小。尺寸100的垃圾箱? floor(mycol/100)*100
。 5号的垃圾箱? floor(mycol/5)*5
。
伯纳。
SELECT b.*,count(*) as total FROM bins b
left outer join table1 a on a.value between b.min_value and b.max_value
group by b.min_value
在表仓包含定义仓MIN_VALUE列和MAX_VALUE。 注意的是,经营者“加入...关于x与y和z”是包容。
表1是数据表的名称
Ofri雷维吾的回答十分接近,但不正确。即使有任何结果的直方图区间的count(*)
将1
。查询需要被修改以使用条件sum
:
SELECT b.*, SUM(a.value IS NOT NULL) AS total FROM bins b
LEFT JOIN a ON a.value BETWEEN b.min_value AND b.max_value
GROUP BY b.min_value;
select "30-34" as TotalRange,count(total) as Count from table_name
where total between 30 and 34
union (
select "35-39" as TotalRange,count(total) as Count from table_name
where total between 35 and 39)
union (
select "40-44" as TotalRange,count(total) as Count from table_name
where total between 40 and 44)
union (
select "45-49" as TotalRange,count(total) as Count from table_name
where total between 45 and 49)
etc ....
只要有不太多的时间间隔,这是一个很好的解决方案。
我由可以被用于自动地生成用于根据指定的数目或大小的块的临时表,用于后来与Ofri雷维吾的解决方案中使用的过程。
CREATE PROCEDURE makebins(numbins INT, binsize FLOAT) # binsize may be NULL for auto-size
BEGIN
SELECT FLOOR(MIN(colval)) INTO @binmin FROM yourtable;
SELECT CEIL(MAX(colval)) INTO @binmax FROM yourtable;
IF binsize IS NULL
THEN SET binsize = CEIL((@binmax-@binmin)/numbins); # CEIL here may prevent the potential creation a very small extra bin due to rounding errors, but no good where floats are needed.
END IF;
SET @currlim = @binmin;
WHILE @currlim + binsize < @binmax DO
INSERT INTO bins VALUES (@currlim, @currlim+binsize);
SET @currlim = @currlim + binsize;
END WHILE;
INSERT INTO bins VALUES (@currlim, @maxbin);
END;
DROP TABLE IF EXISTS bins; # be careful if you have a bins table of your own.
CREATE TEMPORARY TABLE bins (
minval INT, maxval INT, # or FLOAT, if needed
KEY (minval), KEY (maxval) );# keys could perhaps help if using a lot of bins; normally negligible
CALL makebins(20, NULL); # Using 20 bins of automatic size here.
SELECT bins.*, count(*) AS total FROM bins
LEFT JOIN yourtable ON yourtable.value BETWEEN bins.minval AND bins.maxval
GROUP BY bins.minval
这将产生直方图计数只对被填充,该二进制位。大卫 - 韦斯特应该是正的事回调,但出于某种原因,空置的垃圾箱不结果我出现。(尽管使用LEFT JOIN的 - 我不明白为什么)
这应该工作。不那么优雅但仍:
select count(mycol - (mycol mod 10)) as freq, mycol - (mycol mod 10) as label
from mytable
group by mycol - (mycol mod 10)
order by mycol - (mycol mod 10) ASC
select case when total >= 30 and total <= 40 THEN "30-40"
else when total >= 40 and total <= 50 then "40-50"
else "50-60" END as Total , count(total)
group by Total
相等的宽度分箱到箱中的一个给定的计数:
WITH bins AS(
SELECT min(col) AS min_value
, ((max(col)-min(col)) / 10.0) + 0.0000001 AS bin_width
FROM cars
)
SELECT tab.*,
floor((col-bins.min_value) / bins.bin_width ) AS bin
FROM tab, bins;
注意0.0000001有确保与等于max(COL)的值记录不做出自己的箱子只是本身。此外,所述添加剂常数有确保查询不上除零当列中的所有的值是相同的失败。
另外请注意,箱的计数(10中的例子)应与十进制标记被写入,以避免整数除法(未调整bin_width可以是十进制)。