【问题标题】:Calculate SQL Median计算 SQL 中位数
【发布时间】:2015-01-21 16:54:07
【问题描述】:

我试图从这个解决方案中实现一个中位数(除其他外,但这似乎是最简单的中位数代码):Function to Calculate Median in Sql Server

但是,我在应用它时遇到了困难。这是我当前的 SQL 查询。我的目标是在给定的周、月和部门找到CallerComplaintTypeID 的中位数TotalTimeOnCall。我认为我最大的问题是我根本不了解如何应用这个中值函数来实现我的结果。

例如,如果我需要平均值,我可以将 ORDER BY 更改为 GROUP BY,然后改为 AVG(TotalTimeOnCall)。相反,我该如何使用这个中值解决方案来实现这个想法?

这是“原始数据”查询:

WITH rawData as (
SELECT 
    DepartmentName
    ,MONTH(PlacedOnLocal) AS MonthNumber
    ,CASE 
    WHEN Datepart(day, PlacedOnLocal) < 8 THEN '1' 
    WHEN Datepart(day, PlacedOnLocal) < 15 THEN '2' 
    WHEN Datepart(day, PlacedOnLocal) < 22 THEN '3' 
    WHEN Datepart(day, PlacedOnLocal) < 29 THEN '4' 
    ELSE '5' 
    END AS WeekNumber
    ,CallerComplaintTypeID
    ,TotalTimeOnCall
FROM [THE_RELEVANT_TABLE]
WHERE PlacedOnLocal BETWEEN '2014-09-01' AND '2014-12-31'
    AND CallerComplaintTypeID IN (5,89,9,31,203)
    AND TotalTimeOnCall IS NOT NULL
)
SELECT 
DepartmentName,
MonthNumber,
WeekNumber,
CallerComplaintTypeID,
TotalTimeOnCall
FROM
rawData
ORDER BY DepartmentName, MonthNumber, WeekNumber, CallerComplaintTypeID

使用此示例输出:

DepartmentName  MonthNumber WeekNumber  CallerComplaintTypeID   TotalTimeOnCall
Dept_01     9   1   5   654
Dept_01     9   1   5   156
Dept_01     9   1   5   21
Dept_01     9   1   5   67
Dept_01     9   1   5   13
Dept_01     9   1   5   97
Dept_01     9   1   5   87
Dept_01     9   1   5   16

这是上面的中位数解:

SELECT
(
    (
        SELECT MAX(TotalTimeOnCall)
        FROM
            (
                SELECT TOP 50 PERCENT TotalTimeOnCall
                FROM rawData
                WHERE TotalTimeOnCall IS NOT NULL
                ORDER BY TotalTimeOnCall
            ) AS BottomHalf
    )
    +
    (
        SELECT MIN(TotalTimeOnCall)
        FROM
            (
                SELECT TOP 50 PERCENT TotalTimeOnCall
                FROM rawData
                WHERE TotalTimeOnCall IS NOT NULL
                ORDER BY TotalTimeOnCall DESC
            ) AS TopHalf
    )
) / 2 AS Median

【问题讨论】:

  • 该中位数方法不支持每组中位数。它只能计算整个表的中位数。您可以考虑创建一个用户定义的 MEDIAN() 聚合函数。
  • 另外,我怀疑基于ROW_NUMBER() 的替代方案也作为对您所链接问题的答案提出,可能适用于分组中位数,但我不准备详细说明。跨度>
  • @JohnBollinger 谢谢,我能够从效果很好的东西中拼凑出一些东西。

标签: sql sql-server sql-server-2008


【解决方案1】:

这是一个简单的中位数解决方案,可让您获得每组的中位数。

-- Example of how to get median from a set of data
;with cte_my_query as (
    -- this cte simulates the query that would return your data
    select '2016-01-01' as dt, 1 as val
    union 
    select '2016-01-01' as dt, 10 as val
    union 
    select '2016-01-01' as dt, 7 as val
    union 
    select '2016-01-01' as dt, 16 as val
    union 
    select '2016-01-01' as dt, 11 as val
    union 
    select '2016-01-01' as dt, 2 as val
    union
    select '2016-01-01' as dt, 5 as val
    union 
    select '2016-01-02' as dt, 6 as val
    union 
    select '2016-01-02' as dt, 13 as val
    union 
    select '2016-01-02' as dt, 7 as val
    union   
    select '2016-01-02' as dt, 9 as val
    union   
    select '2016-01-02' as dt, 18 as val
)
,cte_dates as (
    -- get the distinct key we want to get median for
    select distinct dt from cte_my_query
)
select  dt, median.val
from    cte_dates
    cross apply (
        -- of the top 50% (below), take the top 1, desc, which is the median value
        select top 1 val from (
            -- for each date, get the top 50% of the values
            select top 50 percent val
            from cte_my_query
            where cte_dates.dt = cte_my_query.dt
            order by dt
        ) as inner_median
        order by inner_median.val desc
    ) median

【讨论】:

    猜你喜欢
    • 2012-10-28
    • 2014-10-27
    • 2019-11-28
    • 1970-01-01
    • 2020-08-08
    • 2017-07-24
    • 2011-01-14
    • 2013-01-20
    • 2010-11-23
    相关资源
    最近更新 更多