2013-12-13 2 views
1

Я работаю с SQL Server 2008Как найти медианы SQL для группировки

Если у меня есть таблица, как, например:

Code Value 
----------------------- 
4  240 
4  299 
4  210 
2  NULL 
2  3 
6  30 
6  80 
6  10 
4  240 
2  30 

Как найти медиану и группу по колонке Code пожалуйста? Чтобы получить ResultSet, как это:

Code Median 
----------------------- 
4  240 
2  16.5 
6  30 

Мне очень нравится это решение для медианы, но, к сожалению, она не включает в себя группу By: https://stackoverflow.com/a/2026609/106227

+0

Возможный дубликат HTTP: //stackoverflow.com/questions/1342898/function-to-calculate-median-in-sql-server – jean

+0

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

+0

В этой связи OP указывает: «Что было бы лучшим способом (если это возможно) сделать это - разрешить вычисление медианного значения (при использовании числового типа данных) в агрегированном запросе?» Обычно это означает, что он плохо использовал группу (AGGREGATE). – jean

ответ

4

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

1 
2 
3 
4 

Медиана здесь 2,5 (т.е. половина группы меньше, и половина группы больше), но метод ранга вернется 3. Чтобы обойти это, вы по существу должны принять верхнее значение из нижней половину группы и нижнее значение верхней половины группы, и принять среднее значение из двух значений.

WITH CTE AS 
( SELECT Code, 
      Value, 
      [half1] = NTILE(2) OVER(PARTITION BY Code ORDER BY Value), 
      [half2] = NTILE(2) OVER(PARTITION BY Code ORDER BY Value DESC) 
    FROM T 
    WHERE Value IS NOT NULL 
) 
SELECT Code, 
     (MAX(CASE WHEN Half1 = 1 THEN Value END) + 
     MIN(CASE WHEN Half2 = 1 THEN Value END))/2.0 
FROM CTE 
GROUP BY Code; 

Example on SQL Fiddle


В SQL Server 2012 можно использовать PERCENTILE_CONT

SELECT DISTINCT 
     Code, 
     Median = PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Value) OVER(PARTITION BY Code) 
FROM T; 

Example on SQL Fiddle

1

SQL Server не имеет функцию для вычисления медианы, но вы можете использовать функцию row_number так:

WITH RankedTable AS (
    SELECT Code, Value, 
     ROW_NUMBER() OVER (PARTITION BY Code ORDER BY VALUE) AS Rnk, 
     COUNT(*) OVER (PARTITION BY Code) AS Cnt 
    FROM MyTable 
) 
SELECT Code, Value 
FROM RankedTable 
WHERE Rnk = Cnt/2 + 1 

Чтобы разработать немного на этом решении, рассмотрим вывод RankedTable КТР:

Code Value Rnk Cnt 
--------------------------- 
4  240  2  3 -- Median 
4  299  3  3 
4  210  1  3 
2  NULL 1  2 
2  3  2  2 -- Median 
6  30  2  3 -- Median 
6  80  3  3 
6  10  1  3 

Теперь из этого набора результатов, если вы возвращаете только те строки, где Rnk равно Cnt/2 + 1 (целочисленное деление), вы получаете только строки со средним значением для каждой группы.

+0

Спасибо Dan. Это почти работает, но не совсем. Я добавил еще одну строку (4, 240). Это приводит к тому, что ваш запрос полностью исключает код 4 из набора результатов. –

+0

Ах да, у вас будут проблемы, когда у вас будет несколько одинаковых значений, так как им присваивается одинаковый RANK. Вместо этого я редактирую свое решение, чтобы использовать функцию ROW_NUMBER, поскольку это присваивает уникальное значение каждой строке. – Dan

+0

Опять же, спасибо Дэн, но он все еще не совсем работает. Я добавил еще одну строку (2,30), и тогда ваш запрос составит 2,30, а не 2,16,5. Решение GarethD ниже обрабатывает ОК. –

Смежные вопросы