【问题标题】:Aggregate rows outside the top聚合顶部以外的行
【发布时间】:2015-10-06 20:23:06
【问题描述】:

假设我们有以下 Fruits 表:

Fruit   | Qty
-------------
Apple   | 2
Apple   | 5
Apple   | 2
Orange  | 3
Orange  | 4
Orange  | 0
Banana  | 2
Banana  | 5
Pear    | 2
Mango   | 1
Mango   | 0

如果我想获得前 3 种水果,我会创建这样的查询:

SELECT TOP 3 Fruit, SUM(Qty) AS Total
FROM Fruits
GROUP BY Fruit
ORDER BY Total DESC

将返回:

Apple   | 9
Orange  | 7
Banana  | 7

但是,如果我想包括不在前 3 名中的水果的总和,我将不得不使用 NOT IN 编写类似这样的内容来排除前 3 名水果:

SELECT 'OTHER' AS Fruit, SUM(Qty) AS Total
FROM Fruits
WHERE Fruit NOT IN (SELECT Fruit FROM (SELECT TOP 3 Fruit, SUM(Qty) AS Total FROM Fruits GROUP BY Fruit ORDER BY Total DESC) AS Test)

如果我想在单个查询中执行此操作,我想我可以使用UNION 组合这两个查询。我已经有了我的计划 B,但我想知道 SQL 是否有任何内置方法来聚合不属于可用于简化查询的最高值的行?

【问题讨论】:

    标签: sql sql-server aggregate sql-server-2014


    【解决方案1】:

    您需要对总和进行排名并为最终结果添加另一个 SUM:

    with cte as
     (
       SELECT Fruit, SUM(Qty) AS Qty,
          ROW_NUMBER() OVER (ORDER BY SUM(Qty) DESC) AS rn
       FROM Fruits 
       GROUP BY Fruit
     )
    select 
       case when rn > 3 then 'Other' else fruit end as fruit, 
       sum(Qty)
    from cte
    group by 
       case when rn > 3 then 'Other' else fruit end
    order by MIN(rn)
    

    Fiddle

    【讨论】:

      【解决方案2】:

      这是通过基于sum(qty) 对行进行排名的一种方法。

      with totals as (SELECT Fruit, SUM(Qty) AS Total FROM Fruits GROUP BY Fruit)
      , rownums as (select *, dense_rank() over(order by total desc) as rank from totals)
      select 
      case when rank > 3 then 'Other' else fruit end as fruit, total
      from rownums
      

      如果other 行需要聚合,请在total 列中再包含一个sum,并在group by 语句中包含group by

      【讨论】:

        【解决方案3】:

        几乎!,可惜你不能把排名放在一个拥有!但你不能。所以你必须有一个嵌套的选择,然后是一个位置。

        加上这个方法,你可以得到任何你想要的组,即 BETWEEN 0 AND 3.. > 3 .. IN(1,3,6) 等

        DECLARE @Fruits TABLE (Fruit NVARCHAR(32),Qty INT)
        INSERT INTO @Fruits(Fruit,Qty)
        VALUES
        ('Apple',2),
        ('Apple',5),
        ('Apple',2),
        ('Orange',3),
        ('Orange',4),
        ('Orange',0),
        ('Banana',2),
        ('Banana',5),
        ('Pear',2),
        ('Mango',1),
        ('Mango',0)
        
        SELECT TOP 3 Fruit, SUM(Qty) AS Total
        FROM @Fruits
        GROUP BY Fruit
        ORDER BY Total DESC
        
        SELECT A.Fruit,A.Total FROM
        (
            SELECT Fruit, SUM(Qty) AS Total,RANK() OVER (ORDER BY SUM(Qty) DESC,Fruit) AS GroupNumber
            FROM @Fruits
            GROUP BY Fruit
        ) AS A
        WHERE GroupNumber > 3 --This bit lets you pick the groups!
        ORDER BY Total DESC
        

        【讨论】:

          猜你喜欢
          • 2014-10-05
          • 1970-01-01
          • 2020-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-15
          相关资源
          最近更新 更多