【问题标题】:How to find the SQL medians for a grouping如何找到分组的 SQL 中位数
【发布时间】:2014-01-01 05:20:24
【问题描述】:

我正在使用 SQL Server 2008

如果我有这样的表:

Code   Value
-----------------------
4      240
4      299
4      210
2      NULL
2      3
6      30
6      80
6      10
4      240
2      30

请问如何通过代码列找到中位数 AND 组? 要获得这样的结果集:

Code   Median
-----------------------
4      240
2      16.5
6      30

我真的很喜欢这个中位数的解决方案,但不幸的是它不包括 Group By: https://stackoverflow.com/a/2026609/106227

【问题讨论】:

  • 我认为该链接实际上并不涉及按第二列分组。
  • 在该链接中,OP 声明“执行此操作的最佳方法是什么(如果可能) - 允许在聚合查询中计算中值(假设为数字数据类型)?”这通常意味着他不喜欢使用 (AGGREGATE) 的组。
  • @StuHarper:“它不包括 Group By”...不,它有!!

标签: sql sql-server tsql group-by median


【解决方案1】:

SQL Server 没有计算中位数的函数,但您可以像这样使用 ROW_NUMBER 函数:

WITH RankedTable AS (
    SELECT Code, Value, 
        ROW_NUMBER() OVER (PARTITION BY Code ORDER BY VALUE) AS Rnk,
        COUNT(*) OVER (PARTITION BY Code) AS Cnt
    FROM MyTable
)
SELECT Code, Value
FROM RankedTable
WHERE Rnk = Cnt / 2 + 1

要详细说明此解决方案,请考虑 RankedTable CTE 的输出:

Code   Value   Rnk    Cnt
---------------------------
4      240     2      3   -- Median
4      299     3      3
4      210     1      3
2      NULL    1      2
2      3       2      2   -- Median
6      30      2      3   -- Median
6      80      3      3
6      10      1      3

现在从这个结果集中,如果你只返回那些 Rnk 等于 Cnt / 2 + 1(整数除法)的行,你只会得到每个组的中值的行。

【讨论】:

  • 谢谢丹。这几乎有效,但不完全有效。我添加了另一行 (4, 240)。这会导致您的查询从结果集中完全丢失代码 4。
  • 啊,是的,当您有多个相同的值时,您会遇到麻烦,因为它们被分配了相同的 RANK。我正在编辑我的解决方案以改用 ROW_NUMBER 函数,因为这将为每一行分配一个唯一值。
  • 再次感谢 Dan,但它仍然无法正常工作。我添加了另一行 (2,30),然后您的查询结果为 2,30 而不是 2,16.5。 GarethD 下面的解决方案可以解决这个问题。
  • 如果原始数据集中甚至不存在这个数字,那么 16,5 怎么可能是中位数?
  • @Dan 中位数不必在原始数据集中。根据Wikipedia“如果有偶数个观测值,则没有单个中间值;中值通常定义为两个中间值的平均值”
【解决方案2】:

当您在每个组中有奇数个成员时,使用排名的解决方案效果很好,即样本中存在中位数,如果您有偶数个成员,排名方法将下降,例如

1
2
3
4

这里的中位数是 2.5(即一半的组更小,一半的组更大),但 rank 方法将返回 3。要解决这个问题,您基本上需要从组的下半部分中获取最高值, 和组上半部分的底值,取两个值的平均值。

WITH CTE AS
(   SELECT  Code,
            Value, 
            [half1] = NTILE(2) OVER(PARTITION BY Code ORDER BY Value), 
            [half2] = NTILE(2) OVER(PARTITION BY Code ORDER BY Value DESC)
    FROM    T
    WHERE   Value IS NOT NULL
)
SELECT  Code,
        (MAX(CASE WHEN Half1 = 1 THEN Value END) + 
        MIN(CASE WHEN Half2 = 1 THEN Value END)) / 2.0
FROM    CTE
GROUP BY Code;

Example on SQL Fiddle


在 SQL Server 2012 中,您可以使用 PERCENTILE_CONT

SELECT  DISTINCT
        Code,
        Median = PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Value) OVER(PARTITION BY Code)
FROM    T;

Example on SQL Fiddle

【讨论】:

    猜你喜欢
    • 2019-04-29
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2021-08-16
    • 1970-01-01
    • 2014-10-25
    相关资源
    最近更新 更多