Function to Calculate Median in SQL Server

前端 未结 30 2803
孤独总比滥情好
孤独总比滥情好 2020-11-22 04:03

According to MSDN, Median is not available as an aggregate function in Transact-SQL. However, I would like to find out whether it is possible to create this functionality (u

相关标签:
30条回答
  • 2020-11-22 04:36

    I try with several alternatives, but due my data records has repeated values, the ROW_NUMBER versions seems are not a choice for me. So here the query I used (a version with NTILE):

    SELECT distinct
       CustomerId,
       (
           MAX(CASE WHEN Percent50_Asc=1 THEN TotalDue END) OVER (PARTITION BY CustomerId)  +
           MIN(CASE WHEN Percent50_desc=1 THEN TotalDue END) OVER (PARTITION BY CustomerId) 
       )/2 MEDIAN
    FROM
    (
       SELECT
          CustomerId,
          TotalDue,
         NTILE(2) OVER (
             PARTITION BY CustomerId
             ORDER BY TotalDue ASC) AS Percent50_Asc,
         NTILE(2) OVER (
             PARTITION BY CustomerId
             ORDER BY TotalDue DESC) AS Percent50_desc
       FROM Sales.SalesOrderHeader SOH
    ) x
    ORDER BY CustomerId;
    
    0 讨论(0)
  • 2020-11-22 04:38

    Median Finding

    This is the simplest method to find the median of an attribute.

    Select round(S.salary,4) median from employee S where (select count(salary) from station where salary < S.salary ) = (select count(salary) from station where salary > S.salary)
    
    0 讨论(0)
  • 2020-11-22 04:38

    For your question, Jeff Atwood had already given the simple and effective solution. But, if you are looking for some alternative approach to calculate the median, below SQL code will help you.

    create table employees(salary int);
    
    insert into employees values(8); insert into employees values(23); insert into employees values(45); insert into employees values(123); insert into employees values(93); insert into employees values(2342); insert into employees values(2238);
    
    select * from employees;
    
    declare @odd_even int; declare @cnt int; declare @middle_no int;
    
    
    set @cnt=(select count(*) from employees); set @middle_no=(@cnt/2)+1; select @odd_even=case when (@cnt%2=0) THEN -1 ELse 0 END ;
    
    
     select AVG(tbl.salary) from  (select  salary,ROW_NUMBER() over (order by salary) as rno from employees group by salary) tbl  where tbl.rno=@middle_no or tbl.rno=@middle_no+@odd_even;

    If you are looking to calculate median in MySQL, this github link will be useful.

    0 讨论(0)
  • 2020-11-22 04:40

    Frequently, we may need to calculate Median not just for the whole table, but for aggregates with respect to some ID. In other words, calculate median for each ID in our table, where each ID has many records. (based on the solution edited by @gdoron: good performance and works in many SQL)

    SELECT our_id, AVG(1.0 * our_val) as Median
    FROM
    ( SELECT our_id, our_val, 
      COUNT(*) OVER (PARTITION BY our_id) AS cnt,
      ROW_NUMBER() OVER (PARTITION BY our_id ORDER BY our_val) AS rnk
      FROM our_table
    ) AS x
    WHERE rnk IN ((cnt + 1)/2, (cnt + 2)/2) GROUP BY our_id;
    

    Hope it helps.

    0 讨论(0)
  • 2020-11-22 04:40

    Building on Jeff Atwood's answer above here it is with GROUP BY and a correlated subquery to get the median for each group.

    SELECT TestID, 
    (
     (SELECT MAX(Score) FROM
       (SELECT TOP 50 PERCENT Score FROM Posts WHERE TestID = Posts_parent.TestID ORDER BY Score) AS BottomHalf)
     +
     (SELECT MIN(Score) FROM
       (SELECT TOP 50 PERCENT Score FROM Posts WHERE TestID = Posts_parent.TestID ORDER BY Score DESC) AS TopHalf)
    ) / 2 AS MedianScore,
    AVG(Score) AS AvgScore, MIN(Score) AS MinScore, MAX(Score) AS MaxScore
    FROM Posts_parent
    GROUP BY Posts_parent.TestID
    
    0 讨论(0)
  • 2020-11-22 04:43

    Justin's example above is very good. But that Primary key need should be stated very clearly. I have seen that code in the wild without the key and the results are bad.

    The complaint I get about the Percentile_Cont is that it wont give you an actual value from the dataset. To get to a "median" that is an actual value from the dataset use Percentile_Disc.

    SELECT SalesOrderID, OrderQty,
        PERCENTILE_DISC(0.5) 
            WITHIN GROUP (ORDER BY OrderQty)
            OVER (PARTITION BY SalesOrderID) AS MedianCont
    FROM Sales.SalesOrderDetail
    WHERE SalesOrderID IN (43670, 43669, 43667, 43663)
    ORDER BY SalesOrderID DESC
    
    0 讨论(0)
提交回复
热议问题