对一组数据进行两级分组。可能吗

时间:2013-06-28 03:14:58

标签: sql sql-server logic grouping

我正在运行一个按国家/地区划分百分比的查询。这样的话:

 select country_of_risk_name, (sum(isnull(fund_weight,0)*100)) as 'FUND WEIGHT' from       OFI_Country_Details
WHERE FIXED_COMP_FUND_CODE = 'X'
GROUP BY country_of_risk_name

这会返回正确的输出。这个范围可以从1个国家到100个国家。我如何编写我的逻辑,它向我显示前5个最高百分比,然后将前5个之外的所有人分组为“其他”类别?示例输出:

  1. 美国 - 50%
  2. 加拿大 - 10%
  3. 法国 - 4%
  4. 西班牙 - 2%
  5. 意大利 - 1.7%
  6. 其他 - 25%

4 个答案:

答案 0 :(得分:2)

SELECT rn, CASE WHEN rn <= 5 THEN x.country_of_risk_name
                ELSE 'Other' END AS country_of_risk_name, 
           SUM(x.[FUND WEIGHT]) AS SumPerc
FROM(      
     SELECT country_of_risk_name,
            CASE WHEN ROW_NUMBER() OVER(ORDER BY SUM(ISNULL(fund_weight,0)*100) DESC) <= 5
                 THEN ROW_NUMBER() OVER(ORDER BY SUM(ISNULL(fund_weight,0)*100) DESC)
                 ELSE 6 END AS rn,
            SUM(ISNULL(fund_weight,0)*100) AS [FUND WEIGHT]
     FROM country_of_risk_name
     WHERE FIXED_COMP_FUND_CODE = 'X'
     GROUP BY country_of_risk_name
     ) x
GROUP BY rn, CASE WHEN rn <= 5 THEN x.country_of_risk_name
                  ELSE 'Other' END 
ORDER BY x.rn

请参阅SQLFiddle

上的演示

答案 1 :(得分:0)

这是使用SQL执行此操作的一种丑陋方式:

select country, sum(perc)
from (
  select 
    case when rn <= 5 then country else 'Other' end 'Country',
    case when rn <= 5 then rn else 6 end rn,    
    perc
  from (
    select *, row_number() over (order by perc desc) rn
    from yourresults
    ) t
) t
group by country, rn
order by rn

我已使用yourresults作为您上述查询的结果 - 将其投放到Common Table Expression中,您应该很高兴:

with yourresults as (
    select country_of_risk_name, (sum(isnull(fund_weight,0)*100)) as 'FUND WEIGHT' 
    from OFI_Country_Details
    where FIXED_COMP_FUND_CODE = 'X'
    group by country_of_risk_name
)
...

答案 2 :(得分:0)

试试这个。

    declare  @country_of_risk_name as table (country varchar(100),
                              FUND decimal(10,2));

    insert into @country_of_risk_name values
      ('USA', 50),
      ('Canada', 10),
      ('France', 4),
      ('Spain', 2),
      ('Italy', 1.7),
      ('Other1', 1.5),
      ('Other2', 1.5),
      ('Other3', 1.5),
      ('Other4', 1.5),
      ('Other5', 1.5),
      ('Other6', 1.5);



    DECLARE @TBL AS TABLE(country_of_risk_name VARCHAR(100), FUND DECIMAL(18,2))

    INSERT INTO @TBL
    SELECT TOP 5 country,SUM(FUND) FROM @country_of_risk_name
      group by country
      ORDER BY SUM(FUND) desc
      select * from @TBL
      UNION ALL 
      select 'other', SUM(tbl1.fund) 
      from @country_of_risk_name tbl1 
      left join @TBL tbl2 on tbl1.country =tbl2.country_of_risk_name 
      where 
          tbl2.country_of_risk_name  is null 

答案 3 :(得分:0)

以下是使用CTE的查询:也是一个有效的solution example

;with TotalPercent(Country_Of_Risk_Name, Fund_Weight)
as(
    select Country_Of_Risk_Name, sum(isnull(Fund_Weight, 0) * 100) Fund_Weight
    from OFI_Country_Details
    where
       FIXED_COMP_FUND_CODE = 'X'
    group by Country_Of_Risk_Name
  ),
  PercentWithRank(Country_Of_Risk_Name, Fund_Weight, RowNumber)
  as (
      select Country_Of_Risk_Name, Fund_Weight, row_number() over (order by Fund_Weight desc) RowNumber
      from TotalPercent
  )
  select Country_Of_Risk_Name, Fund_Weight
  from PercentWithRank
  where
      RowNumber <= 5
  union all
  select 'Other', sum(Fund_Weight) Fund_Weight
  from PercentWithRank
  where
      RowNumber > 5