【问题标题】:Average and Median in one query in Sql Server 2012Sql Server 2012 一次查询中的平均值和中位数
【发布时间】:2014-10-18 23:04:24
【问题描述】:

我的表中有以下数据:

SELECT category, value FROM test
|类别 |价值 | +----------+------+ | 1 | 1 | | 1 | 3 | | 1 | 4 | | 1 | 8 |

现在我正在使用两个单独的查询。

  1. 平均:

      SELECT category, avg(value) as Average
        FROM test
    GROUP BY category
    

    |类别 |价值 | +----------+------+ | 1 | 4 |
  2. 获取中位数:

    SELECT DISTINCT category, 
                    PERCENTILE_CONT(0.5) 
                       WITHIN GROUP (ORDER BY value) 
                       OVER (partition BY category) AS Median
               FROM test
    

    |类别 |价值 | +----------+------+ | 1 | 3.5 |

有没有办法将它们合并到一个查询中?

注意:我知道我也可以使用两个子查询来获取中值,但我更喜欢使用 PERCENTILE_CONT 函数来获取它。

【问题讨论】:

    标签: sql sql-server sql-server-2012 average median


    【解决方案1】:

    AVG 也是一个窗口函数:

    select 
    distinct
    category,
    avg(value) over (partition by category) as average,
    PERCENTILE_CONT(0.5) 
                       WITHIN GROUP (ORDER BY value) 
                       OVER (partition BY category) AS Median
                       from test
    

    【讨论】:

      【解决方案2】:

      我会以稍微不同的方式处理这个问题:

      select category, avg(value) as avg,
             avg(case when 2 * seqnum in (cnt, cnt + 1, cnt + 2) then value end) as median
      from (select t.*, row_number() over (partition by category order by value) as seqnum,
                   count(*) over (partition by category) as cnt
            from test t
           ) t
      group by category;
      

      【讨论】:

      • 对于AVG功能还是要在末尾GROUP BY category。
      • 看起来比之前的答案更复杂...这种方法有更好的性能吗?
      • 它也会返回错误的答案(上面的数据集是 3 而不是 3.5)
      • 如果将 cnt -1, cnt, cnt+ 1 更改为 cnt, cnt+1, cnt + 2 则可以正常工作。
      • @KyleHale 。 . .我相信你在这两个方面都是对的。我对这种方法的偏好是不喜欢将select distinct 与窗口/分析函数混合使用。我发现这些查询的逻辑很难理解。至于性能,需要在您的环境中对您的数据进行测试。
      【解决方案3】:

      我想更彻底地回答这个问题,经过一番挖掘,在对 Dwain Camps 的多种方法的详尽分析中发现了它,以防其他人发现它有用:

      Calculating the Median Value within a Partitioned Set Using T-SQL

      我采用了“他的”第 4 种解决方案(他正在组合/测试其他人的方法),它易于理解并且确实表现良好:

      WITH Counts AS
      (
         SELECT ID, c=COUNT(*)
         FROM #MedianValues
         GROUP BY ID
      )
      SELECT a.ID, Median=AVG(0.+N)
      FROM Counts a
      CROSS APPLY
      (
         SELECT TOP(((a.c - 1) / 2) + (1 + (1 - a.c % 2)))
            N, r=ROW_NUMBER() OVER (ORDER BY N)
         FROM #MedianValues b
         WHERE a.ID = b.ID
         ORDER BY N
      ) p
      WHERE r BETWEEN ((a.c - 1) / 2) + 1 AND (((a.c - 1) / 2) + (1 + (1 - a.c % 2)))
      GROUP BY a.ID;
      

      【讨论】:

        猜你喜欢
        • 2012-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-28
        • 2013-11-02
        • 1970-01-01
        相关资源
        最近更新 更多