自定义聚合函数

时间:2014-04-25 21:02:20

标签: sql sql-server tsql sql-server-2012

如何在SQL Server 2012中创建自定义聚合?我试图得到一个中位数聚合。

类似的东西:

;with cte as 
(
   select top 50 percent val from tbl order by val desc
)
select top 1 from cte

4 个答案:

答案 0 :(得分:2)

您应该使用内置函数percentile_cont()percentil_disc()(请参阅here),具体取决于您为偶数条记录定义中位数的方式。

我认为以下是您想要的:

select percentile_cont(0.5) within group (order by val) as median
from tbl;

这比定义自己的功能容易得多。

答案 1 :(得分:1)

您可能需要阅读以下文章。

http://www.sqlperformance.com/2012/08/t-sql-queries/median

答案 2 :(得分:1)

有一篇有趣的文章探讨了解决此问题的多种方法,并提供了性能分析。它声称percentile_cont()表现最差,而这是最好的:

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;

参考:http://www.sqlperformance.com/2012/08/t-sql-queries/median

答案 3 :(得分:0)

这是将宫本武蔵的答案转化为分组查询的一种方法。我使用了Microsoft的Northwind..Orders表来显示Freight列的中位数计算。

SELECT CustomerID, AVG(1.0 * x.Freight), CASE WHEN COUNT(*)%2=1 THEN COUNT(*) ELSE COUNT(*)/2 END AS Cnt
FROM Orders as O1
CROSS APPLY (
    SELECT Freight FROM Orders as O2
    WHERE O2.CustomerID = O1.CustomerID
     ORDER BY Freight
     OFFSET (SELECT COUNT(*)-1  FROM Orders as O2 WHERE O2.CustomerID = O1.CustomerID) / 2 ROWS
     FETCH NEXT 1 + (1 - (SELECT COUNT(*) FROM Orders as O2 WHERE O2.CustomerID = O1.CustomerID) % 2) ROWS ONLY
) AS x
GROUP BY CustomerID

您在分组查询中可能需要或可能不需要其他聚合,我已经展示了如何获得COUNT(*)。 CROSS APPLY操作为每个CustomerID生成一行,订单数为奇数,并且每个CustomerID生成两行,订单数为偶数,因此要获得COUNT(*)值,您必须除以COUNT(*)值如果是偶数,则在CROSS应用2后,如果是奇数则保持原样。

不确定这是否会有所帮助,并且需要仔细研究以确保它是正确的,但也许这是一个有用的想法。