Какой самый простой (и, надеюсь, не слишком медленный) способ расчета медианы с MySQL? Я использовал AVG(x)
для нахождения среднего значения, но мне трудно найти простой способ вычисления медианы. Сейчас я возвращаю все строки в PHP, выполняю сортировку, а затем выбираю среднюю строку, но наверняка должен быть какой-то простой способ сделать это в одном запросе MySQL.
Пример данных:
id | val
--------
1 4
2 7
3 2
4 2
5 9
6 8
7 3
Сортировка по val
дает 2 2 3 4 7 8 9
, поэтому медиана должна быть 4
, по сравнению с SELECT AVG(val)
которой == 5
.
sql
mysql
statistics
median
Davr
источник
источник
Ответы:
В MariaDB / MySQL:
Стив Коэн отмечает, что после первого прохода @rownum будет содержать общее количество строк. Это можно использовать для определения медианы, поэтому второй проход или соединение не требуется.
Также
AVG(dd.val)
иdd.row_number IN(...)
используется для правильного получения медианы, когда существует четное количество записей. Обоснование:Наконец, MariaDB 10.3.3+ содержит функцию MEDIAN
источник
WHERE 1
наWHERE d.val IS NOT NULL
так, чтобы исключитьNULL
строки, чтобы этот метод был выровнен с роднымAVG
select avg(value) from (select value, row_number from (select a - b as value from a_table join b_table order by value))
Я просто нашел другой ответ онлайн в комментариях :
Убедитесь, что ваши столбцы хорошо проиндексированы, а индекс используется для фильтрации и сортировки. Проверьте с планами объяснения.
Рассчитайте «средний» номер строки. Возможно использовать:
median_row = floor(count / 2)
.Затем выберите его из списка:
Это должно вернуть вам одну строку только с тем значением, которое вы хотите.
Иаков
источник
Я обнаружил, что принятое решение не работает в моей установке MySQL, возвращая пустой набор, но этот запрос работал для меня во всех ситуациях, в которых я его тестировал:
источник
data
и оно используется с двумя именами,x
иy
.К сожалению, ни ответы TheJacobTaylor, ни velcrow не дают точных результатов для текущих версий MySQL.
Ответ липучки сверху близок, но он не рассчитывается правильно для наборов результатов с четным числом строк. Медианы определяются как 1) среднее число на наборах с нечетными номерами, или 2) среднее двух средних чисел на наборах с нечетными числами.
Итак, вот решение Velcro, исправленное для обработки как нечетных, так и четных наборов чисел:
Чтобы использовать это, выполните следующие 3 простых шага:
источник
Я предлагаю более быстрый способ.
Получить количество строк:
SELECT CEIL(COUNT(*)/2) FROM data;
Затем возьмите среднее значение в отсортированном подзапросе:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit @middlevalue) x;
Я проверил это с набором случайных чисел 5x10e6, и он найдет медиану менее чем за 10 секунд.
источник
Комментарий к этой странице в документации MySQL содержит следующее предложение:
источник
Установите и используйте эти статистические функции mysql: http://www.xarg.org/2012/07/statistical-functions-in-mysql/
После этого рассчитать медиану легко:
источник
Большинство из приведенных выше решений работают только для одного поля таблицы, вам может потребоваться получить медиану (50-й процентиль) для многих полей в запросе.
Я использую это:
Вы можете заменить «50» в приведенном выше примере на любой процентиль, это очень эффективно.
Просто убедитесь, что у вас достаточно памяти для GROUP_CONCAT, вы можете изменить это с помощью:
Более подробная информация: http://web.performancerasta.com/metrics-tips-calculation-95th-99th-or-any-percentile-with-single-mysql-query/
источник
У меня есть этот код ниже, который я нашел на HackerRank, и он довольно прост и работает в каждом конкретном случае.
источник
Построение ответа на липучке, для тех из вас, кто должен сделать медиану из чего-то, что сгруппировано по другому параметру:
источник
Вы можете использовать пользовательскую функцию, найденную здесь .
источник
Заботится о количестве нечетных значений - в этом случае дает среднее из двух значений в середине.
источник
Мой код, работающий без таблиц или дополнительных переменных:
источник
GROUP_CONCAT
ограничен 1023 символами, даже если используется внутри другой функции, подобной этой.При желании вы также можете сделать это в хранимой процедуре:
источник
x IS NOT NULL
нужно добавить?CALL median("table","x","x IS NOT NULL")
.Мое решение, представленное ниже, работает в одном запросе без создания таблицы, переменной или даже подзапроса. Кроме того, он позволяет вам получить медиану для каждой группы в групповых запросах (это то, что мне нужно!):
Это работает из-за умного использования group_concat и substring_index.
Но, чтобы разрешить большой group_concat, вы должны установить для group_concat_max_len более высокое значение (по умолчанию 1024 символа). Вы можете установить его так (для текущей сессии sql):
Дополнительная информация для group_concat_max_len: https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
источник
Еще один рифф на ответе Велкроу, но он использует одну промежуточную таблицу и использует переменную, используемую для нумерации строк, чтобы получить счет, а не выполнять дополнительный запрос для его вычисления. Также начинается отсчет, так что первая строка - это строка 0, позволяющая просто использовать Floor и Ceil для выбора медианной строки (строк).
источник
Выше, кажется, работает для меня.
источник
{98,102,102,98}
- это,100
но ваш код дает102
. Это работало нормально для нечетных чисел.Я использовал два запроса:
Они заключены в функцию defn, поэтому все значения могут быть возвращены за один вызов.
Если ваши диапазоны статичны и ваши данные не меняются часто, может быть более эффективно предварительно вычислить / сохранить эти значения и использовать сохраненные значения вместо того, чтобы каждый раз запрашивать с нуля.
источник
так как мне просто нужно решение со средним и процентилем, я сделал простую и довольно гибкую функцию, основанную на выводах в этой теме. Я знаю, что сам рад, если найду «готовые» функции, которые легко включить в мои проекты, поэтому я решил быстро поделиться:
Использование очень просто, пример из моего текущего проекта:
источник
Вот мой путь. Конечно, вы можете поместить это в процедуру :-)
Вы можете избежать переменной
@median_counter
, если вы замените ее:источник
Этот способ включает в себя как четные, так и нечетные числа без подзапроса.
источник
Основываясь на ответе @ bob, это обобщает запрос, чтобы иметь возможность возвращать несколько медиан, сгруппированных по некоторым критериям.
Подумайте, например, о средней цене продажи подержанных автомобилей на автомобильном участке, сгруппированной по годам и месяцам.
источник
Часто нам может потребоваться рассчитать медиану не только для всей таблицы, но и для агрегатов по нашему идентификатору. Другими словами, рассчитайте медиану для каждого идентификатора в нашей таблице, где каждый идентификатор имеет много записей. (хорошая производительность и работает во многих SQL + исправляет проблему четных и шансов, больше о производительности различных методов Median https://sqlperformance.com/2012/08/t-sql-queries/median )
Надеюсь, поможет
источник
MySQL поддерживает оконные функции начиная с версии 8.0, которую вы можете использовать
ROW_NUMBER
илиDENSE_RANK
( НЕ используйте, такRANK
как она присваивает одинаковый ранг одинаковым значениям, как в спортивном рейтинге):источник
Если MySQL имеет ROW_NUMBER, то MEDIAN (вдохновлен этим запросом SQL Server):
IN используется, если у вас есть четное количество записей.
Если вы хотите найти медиану для каждой группы, просто укажите PARTITION BY group в ваших предложениях OVER.
обкрадывать
источник
ROW_NUMBER OVER
, нет PARTITION BY, ничего из этого; это MySql, а не настоящий движок БД, такой как PostgreSQL, IBM DB2, MS SQL Server и т. д .;-).Прочитав все предыдущие, они не соответствовали моему фактическому требованию, поэтому я реализовал свое собственное, которое не нуждается ни в какой процедуре или усложняет утверждения, просто я
GROUP_CONCAT
все значения из столбца, который я хотел получить MEDIAN, и применяя COUNT DIV BY 2 Я извлекаю значение из середины списка, как это делает следующий запрос:(POS - это название столбца, который я хочу получить в медиане)
Я надеюсь, что это может быть полезно для кого-то, как многие другие комментарии были для меня с этого сайта.
источник
Зная точное количество строк, вы можете использовать этот запрос:
куда
<half> = ceiling(<size> / 2.0) - 1
источник
У меня есть база данных, содержащая около 1 миллиарда строк, которые нам необходимы для определения среднего возраста в наборе. Сортировать миллиард строк сложно, но если вы объединяете различные значения, которые можно найти (возраст от 0 до 100), вы можете отсортировать ЭТОТ список и использовать некоторую арифметическую магию, чтобы найти любой процентиль, который вы хотите, следующим образом:
Этот запрос зависит от ваших оконных функций, поддерживающих db (включая ROWS UNBOUNDED PRECEDING), но если у вас его нет, просто объединить aggData CTE с самим собой и объединить все предыдущие итоги в столбец «накопленный», который используется для определения того, какие значение содержит указанный прецентиль. В приведенном выше примере вычисляются значения p10, p25, p50 (медиана), p75 и p90.
-Крис
источник
Взято с: http://mdb-blog.blogspot.com/2015/06/mysql-find-median-nth-element-without.html
Я бы предложил другой способ, без объединения , но работа со строками
я не проверял это с таблицами с большими данными, но с маленькими / средними таблицами это работает просто отлично.
Хорошо, что здесь работает и группировка поэтому может возвращать медиану для нескольких элементов.
Вот тестовый код для тестовой таблицы:
и код для нахождения медианы для каждой группы:
Вывод:
источник
В некоторых случаях медиана рассчитывается следующим образом:
«Медиана» - это «среднее» значение в списке чисел, когда они упорядочены по значению. Для четных наборов значений медиана является средним из двух средних значений . Я создал простой код для этого:
Возвращенное значение $ median будет требуемым результатом :-)
источник