Подтвердить что ты не робот

Получение данных для графика гистограммы

Есть ли способ указать размеры буфера в 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 | 
------------------------------

Я предполагаю, что этого не может быть достигнуто прямым способом, но ссылка на любую связанную хранимую процедуру также будет прекрасной.

4b9b3361

Ответ 1

Это сообщение о супер-быстром и грязном способе создания гистограммы в 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 должно быть смещено в операции ROUNDING на основе увеличения округления, чтобы гарантировать, что первое ведро содержит столько элементов, сколько следующие ковши.

например. с ROUND (numeric_value, -1), numeric_value в диапазоне [0,4] (5 элементов) будут помещены в первое ведро, тогда как [5,14] (10 элементов) во втором, [15,24] в третьем, если только numeric_value смещается соответствующим образом через ROUND (числовое значение - 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 | *               |
+--------+----------+-----------------+

Некоторые примечания: Диапазоны, которые не имеют соответствия, не будут отображаться в счете - у вас не будет нуля в столбце count. Кроме того, я использую Функция ROUND здесь. Вы можете так же легко заменить его TRUNCATE если вы чувствуете, что это имеет больше смысла для вас.

Я нашел его здесь http://blog.shlomoid.com/2011/08/how-to-quickly-create-histogram-in.html

Ответ 2

Ответ Майка Дель Гаудио - это то, как я это делаю, но с небольшим изменением:

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.

Бернардо.

Ответ 3

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, которые определяют ячейки. обратите внимание, что оператор "join... on x BETWEEN y и z" включен.

table1 - это имя таблицы данных

Ответ 4

Отри Равив отвечает очень близко, но неверно. 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;

Ответ 5

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

Пока не так много интервалов, это довольно хорошее решение.

Ответ 6

Я сделал процедуру, которая может быть использована для автоматического создания временной таблицы для ящиков в соответствии с указанным числом или размером для последующего использования с решением 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((@[email protected])/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

Это приведет к подсчету гистограммы только для заполненных бункеров. Дэвид Уэст должен быть прав в своих исправлениях, но почему-то в результате для меня не появляются неопыленные бункеры (несмотря на использование ЛЕВЫЙ ПРИСОЕДИНЕНИЕ - я не понимаю, почему).

Ответ 7

Это должно сработать. Не так элегантно, но все же:

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

через Майк Дель Гаудио

Ответ 8

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 

Ответ 9

В дополнение к отличному ответу fooobar.com/questions/82252/... вы можете использовать инструмент диаграммы phpmyadmin для приятного результата:

enter image description here

enter image description here

Ответ 10

Уравнивание ширины равным образом в заданное количество ящиков:

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 в примере) должно быть записано с десятичной меткой, чтобы избежать целочисленного деления (unadjusted bin_width может быть десятичным).