2014-07-08 5 views
1

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

Например, если диапазон значений составляет от -10..90, а количество диапазонов (баров) - 10, то первый штрих в диаграмме должен показывать количество записей в диапазоне -10..0, а последнее должно показывать номер записей в диапазоне 80..90.

Есть ли лучший способ расчета данных штрих-диаграмм, чем следующее:

  1. Получить мин и макс с select min(value), max(value) from mytable
  2. Вычислить верхнюю и нижнюю границы каждого диапазона (в коде приложения)
  3. Получить количество значений в каждом диапазоне с select count(*) from mytable where value between X and Y

проблема с этим упрощенным подходом является то, что отдельный запрос нужно будет ISS чтобы найти количество значений в каждом диапазоне, можно ли сделать это более эффективным, например. путем динамического создания запроса и использования GROUP BY?

ответ

1
SELECT * FROM my_table; 
+----+-----+ 
| id | val | 
+----+-----+ 
| 1 | 19 | 
| 2 | 10 | 
| 3 | 6 | 
| 4 | 29 | 
| 6 | 27 | 
| 7 | 20 | 
| 8 | 11 | 
| 9 | 12 | 
| 13 | 16 | 
| 14 | 38 | 
| 15 | 8 | 
| 16 | 22 | 
| 17 | 23 | 
| 18 | 16 | 
| 19 | 20 | 
| 20 | 18 | 
| 28 | 18 | 
| 29 | 7 | 
| 30 | 10 | 
| 31 | 34 | 
| 32 | 11 | 
| 33 | 17 | 
| 34 | 15 | 
| 35 | 12 | 
| 36 | 19 | 
| 37 | 15 | 
| 38 | 18 | 
| 39 | 24 | 
| 40 | 10 | 
| 41 | 19 | 
| 42 | 25 | 
| 43 | 22 | 
| 59 | 27 | 
| 60 | 14 | 
| 61 | 17 | 
| 62 | 25 | 
| 63 | 28 | 
| 64 | 20 | 
| 65 | 10 | 
| 66 | 18 | 
| 67 | 22 | 
| 68 | 12 | 
| 69 | 18 | 
| 70 | 31 | 
| 71 | 22 | 
| 72 | 23 | 
| 73 | 20 | 
| 74 | 12 | 
| 75 | 10 | 
| 76 | 9 | 
| 77 | 21 | 
| 78 | 18 | 
| 79 | 14 | 
| 80 | 17 | 
| 81 | 7 | 
| 82 | 21 | 
| 83 | 11 | 
| 84 | 16 | 
| 85 | 19 | 
| 86 | 30 | 
| 87 | 11 | 
| 88 | 18 | 
| 89 | 26 | 
| 90 | 16 | 
+----+-----+ 

SELECT CEILING(((1+val-(SELECT MIN(val) FROM my_table)))/ROUND((SELECT MAX(val)-MIN(val) FROM my_table)/8)) x 
    , COUNT(*) 
    , GROUP_CONCAT(LPAD(val,2,0) ORDER BY val) n 
    FROM my_table 
GROUP 
    BY CEILING(((1+val-(SELECT MIN(val) FROM my_table)))/ROUND((SELECT MAX(val)-MIN(val) FROM my_table)/8)); 
+------+----------+----------------------------------------------------+ 
| x | COUNT(*) | n             | 
+------+----------+----------------------------------------------------+ 
| 1 |  5 | 06,07,07,08,09          | 
| 2 |  13 | 10,10,10,10,10,11,11,11,11,12,12,12,12    | 
| 3 |  11 | 14,14,15,15,16,16,16,16,17,17,17     | 
| 4 |  17 | 18,18,18,18,18,18,18,19,19,19,19,20,20,20,20,21,21 | 
| 5 |  9 | 22,22,22,22,23,23,24,25,25       | 
| 6 |  5 | 26,27,27,28,29          | 
| 7 |  2 | 30,31            | 
| 8 |  1 | 34             | 
| 9 |  1 | 38             | 
+------+----------+----------------------------------------------------+ 
+0

Я не думаю, что это мне помогает. В вашем примере группы сами являются значениями, это не относится ко мне. Если вы думаете, что я ошибаюсь, не могли бы вы переработать этот пример так, чтобы 'dt' был десятичным столбцом, а группы состояли из значений в диапазонах с одинаковой шириной? –

+0

См. Edit - может быть, не совсем правильно, но что-то вроде – Strawberry

0
SELECT CASE 
WHEN (max(numb) - min(numb) BETWEEN xx AND yy THEN zz 
WHEN (max(numb) - min(numb) BETWEEN zz AND aa THEN cc 

будет обрабатывать ваши размеры вашей гистограммы и GROUP BY в запросе другой даст вам значение в каждом дистрибутиве.

0

Если я правильно понимаю ваш вопрос, диапазоны неизвестны, и вы должны определять их динамически. Найдите значения min и max, как вы это делали. Используя курсор, вычислите верхнюю и нижнюю границы для каждого диапазона и сохраните результаты во временную таблицу, содержащую такие поля, как rangeLabel, lowerBound, upperBound. Выберите таблицу temp и найдите подсчеты с помощью подзапроса:

SELECT rangeLabel, (SELECT Count(*) FROM mytable 
    WHERE value BETWEEN temp.lowerBound AND temp.Upperbound) as myCount 
FROM temp 
Смежные вопросы