Yaa*_*lis 212 sql sql-server aggregate-functions median
根据MSDN,Median不能作为Transact-SQL中的聚合函数使用.但是,我想知道是否可以创建此功能(使用Create Aggregate函数,用户定义函数或其他方法).
这样做的最佳方式(如果可能) - 允许在聚合查询中计算中值(假设数值数据类型)?
Jef*_*ood 194
如果您使用的是SQL 2005或更高版本,这对于表中的单个列来说是一个很好的,简单的中位数计算:
SELECT
(
 (SELECT MAX(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts ORDER BY Score) AS BottomHalf)
 +
 (SELECT MIN(Score) FROM
   (SELECT TOP 50 PERCENT Score FROM Posts ORDER BY Score DESC) AS TopHalf)
) / 2 AS Median
Jus*_*ant 129
有很多方法可以做到这一点,性能差异很大.这是一个特别优化的解决方案,来自Medians,ROW_NUMBERs和性能.当涉及到执行期间生成的实际I/O时,这是一个特别优化的解决方案 - 它看起来比其他解决方案更昂贵,但它实际上要快得多.
该页面还包含对其他解决方案和性能测试详细信息的讨论.请注意,如果有多个行具有相同的中间列值,则使用唯一列作为消歧器.
与所有数据库性能方案一样,始终尝试使用真实硬件上的实际数据测试解决方案 - 您永远不知道对SQL Server优化程序的更改或环境中的特性何时会使正常快速的解决方案变慢.
DECLARE @c BIGINT = (SELECT COUNT(*) FROM dbo.EvenRows);
SELECT AVG(1.0 * val)
FROM (
    SELECT val FROM dbo.EvenRows
     ORDER BY val
     OFFSET (@c - 1) / 2 ROWS
     FETCH NEXT 1 + (1 - @c % 2) ROWS ONLY
) AS x;
Sim*_*ver 78
在SQL Server 2012中,您应该使用PERCENTILE_CONT:
SELECT SalesOrderID, OrderQty,
    PERCENTILE_CONT(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
另见:http://blog.sqlauthority.com/2011/11/20/sql-server-introduction-to-percentile_cont-analytic-functions-introduced-in-sql-server-2012/
Sir*_*bin 21
我原来的快速回答是:
select  max(my_column) as [my_column], quartile
from    (select my_column, ntile(4) over (order by my_column) as [quartile]
         from   my_table) i
--where quartile = 2
group by quartile
这将一举为您提供中位数和四分位数范围.如果你真的只想要一行是中位数,那么取消注释where子句.
当你坚持使用解释计划时,60%的工作是对数据进行排序,这在计算像这样的位置相关统计数据时是不可避免的.
我修改了答案,遵循RobertŠevčík-Robajz在以下评论中提出的出色建议:
;with PartitionedData as
  (select my_column, ntile(10) over (order by my_column) as [percentile]
   from   my_table),
MinimaAndMaxima as
  (select  min(my_column) as [low], max(my_column) as [high], percentile
   from    PartitionedData
   group by percentile)
select
  case
    when b.percentile = 10 then cast(b.high as decimal(18,2))
    else cast((a.low + b.high)  as decimal(18,2)) / 2
  end as [value], --b.high, a.low,
  b.percentile
from    MinimaAndMaxima a
  join  MinimaAndMaxima b on (a.percentile -1 = b.percentile) or (a.percentile = 10 and b.percentile = 10)
--where b.percentile = 5
当您拥有偶数个数据项时,这应该计算正确的中位数和百分位数值.如果您只想要中位数而不是整个百分位数分布,请再次取消注释最终的where子句.
l--*_*''' 18
更好的是:
SELECT @Median = AVG(1.0 * val)
FROM
(
    SELECT o.val, rn = ROW_NUMBER() OVER (ORDER BY o.val), c.c
    FROM dbo.EvenRows AS o
    CROSS JOIN (SELECT c = COUNT(*) FROM dbo.EvenRows) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2);
来自大师自己,Itzik Ben-Gan!
MS SQL Server 2012(及更高版本)具有PERCENTILE_DISC函数,该函数计算排序值的特定百分位数.PERCENTILE_DISC(0.5)将计算中位数 - https://msdn.microsoft.com/en-us/library/hh231327.aspx