2015-12-14 6 views
0

Мне нужно вычислить медианную для нескольких полей в запросе и сгруппировать ее одним из столбцов. Есть ли способ легко вычислить Median в SQL Server 2008 R2? У меня возникают проблемы с его вычислением в 2008 R2.Вычисление медианы в SQL Server 2008 R2

Table structure: 
PatientName (need to calculate count group by PatientType) 
PatientType (should be used to group the query by), 
minutes1, 
minutes2, 
minutes3, 
minutes4, 
minutes5 

End Result: 
PatientCount (Group by PatientType), 
Median For minutes1 (Group by PatientType), 
Median For minutes2 (Group by PatientType), 
Median For minutes3 (Group by PatientType), 
Median For minutes4 (Group by PatientType), 
Median For minutes5 (Group by PatientType) 
+1

Легко, нет. Но это может быть сделано. Вы можете использовать PERCENTILE_DISC, но это было недоступно до 2012 года. Даже тогда я не уверен, является ли это истинной медианной или использует ближайшее меньшее значение в четных наборах. Например, если значения «1,3,5,7' являются медианными, это 4, но 3 будет достаточно близко для вас? –

+0

В прошлом я использовал PERCENTILE_DISC или PERCENTILE_CONT, но они полезны только в 2012 году или выше. Кроме того, мне нужна настоящая медиана. – NonProgrammer

ответ

2

Вы можете попробовать это:

SELECT PatientType, minutes1=(
    SELECT AVG(1.0 * minutes1) 
    FROM 
    (
    SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c 
    FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3 
    CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c 
) AS x 
    WHERE rn IN ((c + 1)/2, (c + 2)/2) 
), minutes2=(
    SELECT AVG(1.0 * minutes2) 
    FROM 
    (
    SELECT t3.minutes2, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c 
    FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3 
    CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c 
) AS x 
    WHERE rn IN ((c + 1)/2, (c + 2)/2) 
), minutes3=(
    SELECT AVG(1.0 * minutes1) 
    FROM 
    (
    SELECT t3.minutes3, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c 
    FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3 
    CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c 
) AS x 
    WHERE rn IN ((c + 1)/2, (c + 2)/2) 
), minutes4=(
    SELECT AVG(1.0 * minutes4) 
    FROM 
    (
    SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c 
    FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3 
    CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c 
) AS x 
    WHERE rn IN ((c + 1)/2, (c + 2)/2) 
), minutes5=(
    SELECT AVG(1.0 * minutes5) 
    FROM 
    (
    SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c 
    FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3 
    CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c 
) AS x 
    WHERE rn IN ((c + 1)/2, (c + 2)/2) 
) 
FROM Table t1 
GROUP BY PatientType 

и есть, вероятно, гораздо лучше, и это, вероятно, может быть оптимизирован совсем немного.

+0

Что делать, если у этих полей есть нули? Вы предложили бы заменить нули 0 или не принимать их в мои вычисления при расчете медианного? – NonProgrammer

+1

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