¿Hay alguna forma de especificar tamaños de contenedor en MySQL? En este momento, estoy probando la siguiente consulta SQL:
select total, count(total) from faults GROUP BY total;
Los datos que se están generando son lo suficientemente buenos, pero hay demasiadas filas. Lo que necesito es una forma de agrupar los datos en contenedores predefinidos. Puedo hacer esto desde un lenguaje de scripting, pero ¿hay alguna forma de hacerlo directamente en SQL?
Ejemplo:
+-------+--------------+
| 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 |
------------------------
Lo que estoy buscando:
+------------+---------------+
| total | count(total) |
+------------+---------------+
| 30 - 40 | 23 |
| 40 - 50 | 15 |
| 50 - 60 | 51 |
| 60 - 70 | 45 |
------------------------------
Supongo que esto no se puede lograr de una manera sencilla, pero una referencia a cualquier procedimiento almacenado relacionado también estaría bien.
Respuestas:
Lo encontré aquí http://blog.shlomoid.com/2011/08/how-to-quickly-create-histogram-in.html
fuente
La respuesta de Mike DelGaudio es la forma en que lo hago, pero con un ligero cambio:
select floor(mycol/10)*10 as bin_floor, count(*) from mytable group by 1 order by 1
¿La ventaja? Puede hacer que los contenedores sean tan grandes o pequeños como desee. ¿Contenedores de tamaño 100?
floor(mycol/100)*100
. ¿Contenedores de tamaño 5?floor(mycol/5)*5
.Bernardo.
fuente
concat(floor(mycol/5)*5," to ",floor(mycol/5)*5+5)
round(mycol, -2)
de la respuesta aceptada, ya que permite al usuario definir cualquier "rango" no decimal. Solo usaría enround
lugar de,floor
ya que redondea correctamente los números.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
Los contenedores de la tabla contienen columnas min_value y max_value que definen los contenedores. tenga en cuenta que el operador "unirse ... en x ENTRE yyz" es inclusivo.
table1 es el nombre de la tabla de datos
fuente
La respuesta de Ofri Raviv es muy cercana pero incorrecta. La
count(*)
habrá1
incluso si hay cero resultados en un intervalo de histograma. La consulta debe modificarse para usar un condicionalsum
: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;
fuente
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 ....
Siempre que no haya demasiados intervalos, esta es una solución bastante buena.
fuente
Hice un procedimiento que se puede usar para generar automáticamente una tabla temporal para bins de acuerdo con un número o tamaño específico, para su uso posterior con la solución de Ofri Raviv.
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
Esto generará el recuento del histograma solo para los contenedores que se llenan. David West debería tener razón en su corrección, pero por alguna razón, los contenedores vacíos no aparecen en el resultado para mí (a pesar del uso de LEFT JOIN, no entiendo por qué).
fuente
Eso debería funcionar. No tan elegante pero aún así:
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
a través de Mike DelGaudio
fuente
SELECT CASE WHEN total <= 30 THEN "0-30" WHEN total <= 40 THEN "31-40" WHEN total <= 50 THEN "41-50" ELSE "50-" END as Total, count(*) as count GROUP BY Total ORDER BY Total;
fuente
Agrupación de igual ancho en un recuento dado de agrupaciones:
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;
Tenga en cuenta que el 0,0000001 está ahí para asegurarse de que los registros con el valor igual a max (col) no hagan su propio contenedor por sí mismos. Además, la constante aditiva está ahí para asegurarse de que la consulta no falle en la división por cero cuando todos los valores de la columna son idénticos.
También tenga en cuenta que el recuento de bins (10 en el ejemplo) debe escribirse con una marca decimal para evitar la división de enteros (el bin_width no ajustado puede ser decimal).
fuente
WITH something AS
es muy útil si usted tiene que calcular el valor que va en los contenedores.Además de la excelente respuesta https://stackoverflow.com/a/10363145/916682 , puede usar la herramienta de gráficos phpmyadmin para obtener un buen resultado:
fuente