Простой способ вычислить медиану с MySQL

Это может быть очень трудным вызовом для создания...

Один указатель я могу дать: объект может реализовать много интерфейсов, пока объект может только наследовать один базовый класс (на современном языке OO как c#, я знаю, что C++ имеет множественное наследование - но разве который не осужден?)

191
задан Török Gábor 11 March 2010 в 06:22
поделиться

5 ответов

Если MySQL имеет ROW_NUMBER, то МЕДИАНА (на основе этого запроса SQL Server):

WITH Numbered AS 
(
SELECT *, COUNT(*) OVER () AS Cnt,
    ROW_NUMBER() OVER (ORDER BY val) AS RowNum
FROM yourtable
)
SELECT id, val
FROM Numbered
WHERE RowNum IN ((Cnt+1)/2, (Cnt+2)/2)
;

IN используется, если у вас четное число записей.

Если вы хотите найти медиана на группу, затем просто PARTITION BY group в ваших предложениях OVER.

Роб

0
ответ дан 23 November 2019 в 05:34
поделиться

Я только что нашел другой ответ в Интернете в комментариях :

Для медиан почти в любом SQL:

 ВЫБЕРИТЕ x.val из данных x, данных y
ГРУППА ПО x.val
ИМЕЮЩУЮ СУММУ (ЗНАК (1-ЗНАК (y.val-x.val))) = (СЧЁТ (*) + 1) / 2

Убедитесь, что ваши столбцы хорошо проиндексированы, а индекс используется для фильтрации и сортировки. Сверьте с планами объяснения.

select count(*) from table --find the number of rows

Вычислите "средний" номер строки. Можно использовать: median_row = floor (count / 2) .

Затем выберите его из списка:

select val from table order by val asc limit median_row,1

Это должно вернуть вам одну строку с нужным вам значением.

Jacob

58
ответ дан 23 November 2019 в 05:34
поделиться

Комментарий к этой странице в документации MySQL следующее предложение:

-- (mostly) High Performance scaling MEDIAN function per group
-- Median defined in http://en.wikipedia.org/wiki/Median
--
-- by Peter Hlavac
-- 06.11.2008
--
-- Example Table:

DROP table if exists table_median;
CREATE TABLE table_median (id INTEGER(11),val INTEGER(11));
COMMIT;


INSERT INTO table_median (id, val) VALUES
(1, 7), (1, 4), (1, 5), (1, 1), (1, 8), (1, 3), (1, 6),
(2, 4),
(3, 5), (3, 2),
(4, 5), (4, 12), (4, 1), (4, 7);



-- Calculating the MEDIAN
SELECT @a := 0;
SELECT
id,
AVG(val) AS MEDIAN
FROM (
SELECT
id,
val
FROM (
SELECT
-- Create an index n for every id
@a := (@a + 1) mod o.c AS shifted_n,
IF(@a mod o.c=0, o.c, @a) AS n,
o.id,
o.val,
-- the number of elements for every id
o.c
FROM (
SELECT
t_o.id,
val,
c
FROM
table_median t_o INNER JOIN
(SELECT
id,
COUNT(1) AS c
FROM
table_median
GROUP BY
id
) t2
ON (t2.id = t_o.id)
ORDER BY
t_o.id,val
) o
) a
WHERE
IF(
-- if there is an even number of elements
-- take the lower and the upper median
-- and use AVG(lower,upper)
c MOD 2 = 0,
n = c DIV 2 OR n = (c DIV 2)+1,

-- if its an odd number of elements
-- take the first if its only one element
-- or take the one in the middle
IF(
c = 1,
n = 1,
n = c DIV 2 + 1
)
)
) a
GROUP BY
id;

-- Explanation:
-- The Statement creates a helper table like
--
-- n id val count
-- ----------------
-- 1, 1, 1, 7
-- 2, 1, 3, 7
-- 3, 1, 4, 7
-- 4, 1, 5, 7
-- 5, 1, 6, 7
-- 6, 1, 7, 7
-- 7, 1, 8, 7
--
-- 1, 2, 4, 1

-- 1, 3, 2, 2
-- 2, 3, 5, 2
--
-- 1, 4, 1, 4
-- 2, 4, 5, 4
-- 3, 4, 7, 4
-- 4, 4, 12, 4


-- from there we can select the n-th element on the position: count div 2 + 1 
8
ответ дан 23 November 2019 в 05:34
поделиться

Вы можете использовать пользователя -определенная функция, которая находится здесь .

3
ответ дан 23 November 2019 в 05:34
поделиться

Я использовал подход с двумя запросами:

  • первый для получения count, min, max и avg
  • второй (подготовленный оператор) с «LIMIT @ count / 2, 1 "и" ORDER BY .. "для получения среднего значения

Они заключены в функцию defn, поэтому все значения могут быть возвращены из одного вызова.

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

1
ответ дан 23 November 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: