Question

Y at-il un moyen de spécifier la taille bin dans MySQL? En ce moment, je suis en train de la requête SQL suivante:

select total, count(total) from faults GROUP BY total;

Les données qui est généré est assez bon, mais il y a trop de lignes. Ce que je besoin est un moyen de regrouper les données dans des bacs prédéfinis. Je peux le faire à partir d'un langage de script, mais est-il un moyen de le faire directement dans SQL?

Exemple:

+-------+--------------+
| 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 | 
------------------------

Ce que je cherche:

+------------+---------------+
| total      | count(total)  |
+------------+---------------+
|    30 - 40 |            23 | 
|    40 - 50 |            15 | 
|    50 - 60 |            51 | 
|    60 - 70 |            45 | 
------------------------------

Je suppose que cela ne peut pas être réalisé de manière avant droit, mais une référence à une procédure stockée connexe serait bien aussi.

Était-ce utile?

La solution

  

Ceci est un post sur un moyen super rapide et sale pour créer un histogramme   MySQL pour les valeurs numériques.

     

Il y a plusieurs autres façons de créer des histogrammes qui sont mieux et   plus souple, en utilisant des déclarations de cas et d'autres types de logique complexe.   Cette méthode me gagne au fil du temps et encore, car il est tellement facile   à modifier pour chaque cas d'utilisation, et si courte et concise. Voici comment vous   faire:

SELECT ROUND(numeric_value, -2)    AS bucket,
       COUNT(*)                    AS COUNT,
       RPAD('', LN(COUNT(*)), '*') AS bar
FROM   my_table
GROUP  BY bucket;
     

Il suffit de changer numeric_value à ce que votre colonne, changer la   incrément d'arrondi, et c'est tout. J'ai fait les barres pour être en   échelle logarithmique, de sorte qu'ils ne poussent pas trop quand vous avez   de grandes valeurs.

     

numeric_value devrait être compensé dans l'opération Arrondi, en fonction de l'incrément d'arrondi, afin d'assurer le premier seau contient autant d'éléments que les seaux suivants.

     

par exemple. avec ROUND (numeric_value, -1), numeric_value dans la gamme [0,4] (5 éléments) sera placé dans le premier godet, tandis que [5,14] (10) des éléments en second, [15,24] à la troisième, à moins que numeric_value est décalée de façon appropriée par l'intermédiaire d'ROUND (numeric_value - 5, -1).

     

Ceci est un exemple d'une telle requête sur certaines données aléatoires qui semble assez   sucré. Assez bon pour une évaluation rapide des données.

+--------+----------+-----------------+
| 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 | *               |
+--------+----------+-----------------+
     

Quelques notes: plages qui ont aucune correspondance ne figurera pas dans le compte -   vous n'aurez pas un zéro dans la colonne de comptage. , J'utilise aussi la   ROND fonction ici. Vous pouvez aussi remplacer facilement avec TRUNCATE   si vous sentez qu'il est plus logique de vous.

Je l'ai trouvé ici http://blog.shlomoid.com /2011/08/how-to-quickly-create-histogram-in.html

Autres conseils

La réponse de Mike DelGaudio est la façon dont je le fais, mais avec un léger changement:

select floor(mycol/10)*10 as bin_floor, count(*)
from mytable
group by 1
order by 1

L'avantage? Vous pouvez faire les poubelles aussi grand ou aussi petit que vous voulez. Bins de taille 100? floor(mycol/100)*100. Bins de taille 5? floor(mycol/5)*5.

Bernardo.

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

Les bacs de table contient des colonnes MIN_VALUE et max_value qui définissent les bacs. Notez que l'opérateur « se joindre à ... sur x ENTRE y et z » est inclus.

table1 est le nom de la table de données

La réponse de Ofri Raviv est très proche mais incorrect. Le count(*) sera 1 même s'il y a des résultats nuls dans un intervalle d'histogramme. La requête doit être modifié pour utiliser un sum conditionnel:

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 ....

Tant qu'il n'y a pas trop d'intervalles, c'est une solution assez bonne.

I fait une procédure qui peut être utilisée pour générer automatiquement une table temporaire de bacs en fonction d'un certain nombre ou de la taille, pour une utilisation ultérieure avec une solution 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

Cela va générer le compte de l'histogramme uniquement pour les bacs qui sont peuplées. David Ouest devrait avoir raison dans sa correction, mais pour une raison quelconque, les bacs inhabitées ne figurent pas dans le résultat pour moi. (Malgré l'utilisation d'un LEFT JOIN - Je ne comprends pas pourquoi)

Cela devrait fonctionner. Pas si élégant mais encore:

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

par Mike DelGaudio

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 

En plus de grande réponse https://stackoverflow.com/a/10363145/916682 , vous pouvez utiliser phpmyadmin outil graphique pour un bon résultat:

entrer image description ici

entrer image description ici

binning largeur égale à un nombre donné de cases:

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;

Notez que le 0,0000001 est là pour vous assurer que les enregistrements avec la valeur égale au maximum (col) ne font pas de son propre balconnet juste par lui-même. En outre, la constante additif est là pour vous assurer que la requête ne manque pas de division par zéro lorsque toutes les valeurs de la colonne sont identiques.

Notez également que le nombre de bacs (10 dans l'exemple) doit être écrit avec une marque décimale pour éviter la division entière (le bin_width non ajusté peut être décimal).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top