Domanda

C'è un modo per specificare le dimensioni dei contenitori in MySQL?In questo momento, sto provando la seguente query SQL:

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

I dati generati sono abbastanza buoni ma ci sono troppe righe.Ciò di cui ho bisogno è un modo per raggruppare i dati in contenitori predefiniti.Posso farlo da un linguaggio di scripting, ma c'è un modo per farlo direttamente in SQL?

Esempio:

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

Quello che sto cercando:

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

Immagino che ciò non possa essere ottenuto in modo semplice, ma andrebbe bene anche un riferimento a qualsiasi procedura memorizzata correlata.

È stato utile?

Soluzione

  

Questo è un post di un modo super veloce-e-sporco per creare un istogramma   in MySQL per i valori numerici.

     

Ci sono diversi altri modi per creare istogrammi che sono meglio e   più flessibile, utilizzando istruzioni CASE e altri tipi di logica complessa.   Questo metodo mi conquista di volta in volta dal momento che è proprio così facile   modificare per ciascun caso d'uso, e così breve e concisa. Ecco come   farlo:

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

Basta cambiare numeric_value a tutto ciò che la colonna è, cambiare la   arrotondamento incremento, e questo è tutto. Ho fatto le barre di essere in   scala logaritmica, in modo che essi non crescono troppo quando si ha   grandi valori.

     

numeric_value dovrebbe essere compensato nella operazione di arrotondamento, basato sull'incremento arrotondamento, al fine di garantire il primo segmento contiene tanti elementi come i seguenti secchi.

     

es. con ROUND (numeric_value, -1), numeric_value nell'intervallo [0,4] (5 elementi) saranno collocati nel primo segmento, mentre [5,14] (10 elementi) a seconda, [15,24] nel terzo, a meno numeric_value è compensato in modo appropriato tramite ROUND (numeric_value - 5, -1).

     

Questo è un esempio di tale interrogazione su alcuni dati casuali che sembra piuttosto   dolce. Abbastanza buono per una rapida valutazione dei dati.

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

Alcune note: Gamme che non hanno alcuna corrispondenza non comparirà nel conteggio -   non si avrà uno zero nella colonna conteggio. Inoltre, sto usando il   ROUND funzione di qui. Si può altrettanto facilmente sostituirlo con TRUNCATE   se si sente che ha più senso per voi.

L'ho trovato qui http://blog.shlomoid.com /2011/08/how-to-quickly-create-histogram-in.html

Altri suggerimenti

La risposta di Mike DelGaudio è il modo in cui lo faccio, ma con un leggero cambiamento:

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

Il vantaggio?Puoi rendere i contenitori grandi o piccoli quanto desideri.Bidoni da 100? floor(mycol/100)*100.Bidoni di dimensione 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

I bidoni tabella contiene colonne MIN_VALUE e max_value che definiscono i bidoni. notare che l'operatore "join ... su x TRA yez" è inclusiva.

Tabella 1 è il nome della tabella di dati

La risposta di Ofri Raviv è molto vicino ma non corretto. Il count(*) sarà 1 anche se ci sono zero risultati in un intervallo di istogramma. La query ha bisogno di essere modificati per utilizzare un sum condizionale:

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

Fino a quando non ci sono troppi intervalli, questa è una soluzione abbastanza buona.

feci una procedura che può essere utilizzato per generare automaticamente una tabella temporanea per contenitori secondo un numero o dimensione specificata, per un uso successivo con la soluzione di 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

Questo genererà il conteggio istogramma solo per i contenitori che sono popolate. David West dovrebbe essere ragione nella sua correzione, ma per qualche ragione, bidoni disabitate non appaiono nel risultato per me. (Nonostante l'uso di un LEFT JOIN - non capisco perché)

Che dovrebbe funzionare. Non è così elegante, ma ancora:

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

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 

In aggiunta a grande risposta https://stackoverflow.com/a/10363145/916682 , è possibile utilizzare phpMyAdmin strumento grafico per un bel risultato:

entrare descrizione dell'immagine qui

entrare descrizione dell'immagine qui

La parità di larghezza binning in un determinato numero di bidoni:

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;

Si noti che il 0,0000001 è lì per fare in modo che i record con il valore pari a max (Col) non fanno il proprio bin solo per sé. Inoltre, la costante additivo è lì per assicurarsi che la query non sicuro sulla divisione per zero quando tutti i valori nella colonna sono identici.

Si noti inoltre che il conteggio di contenitori (10 nell'esempio) deve essere scritto con un punto decimale per evitare la divisione intera (il bin_width senza correzione può essere decimale).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top