【问题标题】:Summing Top N categories in SQL with all others in "Other"将 SQL 中的前 N ​​个类别与“其他”中的所有其他类别相加
【发布时间】:2020-08-07 19:27:22
【问题描述】:

我正在尝试对数据集进行分类,其中前 3 名记录计数的描述类别将汇总为前 3 名,而所有其他类别将计入“其他”类别(我这样做是为了SSRS 报告)。我使用窗口函数来组织每个类别,但我很难创建最终结果。

     declare @t table(id int, description varchar(50))
     insert into @t values(123, 'Cardiac'),
                 (124, 'Cardiac'),
                 (125, 'Cardiac'),
                 (126, 'Cardiac'),
                 (222, 'Digestive'),
                 (223, 'Digestive'),
                 (224, 'Digestive'),
                 (225, 'Digestive'),
                 (226, 'Digestive'),
                 (333, 'Muscular'),
                 (334, 'Muscular'),
                 (335, 'Muscular'),
                 (336, 'Muscular'),
                 (444, 'Nose'),
                 (445, 'Nose'),
                 (446, 'Nose'),
                 (447, 'Nose'),
                 (448, 'Nose'),
                 (449, 'Nose'),
                 (555, 'Ear'),
                 (555, 'Ear'),
                 (666, 'Mouth')

到目前为止我已经写了这个:

    select *, row_number()over(partition by description order by id) as ranks
    from @t
    group by id, description

我想要的结果是这样的:

     Description   Count
       Nose          6
       Digestive     5
       Cardiac       4
       Muscular      4
       Other         3

我认为它涉及使用带有 count() 的窗口函数,但我似乎无法弄清楚。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    您可以使用两个级别的聚合:

    select (case when seqnum <= 4 then description else 'Other' end), sum(cnt) as cnt
    from (select description, count(*) as cnt,
                 row_number() over (order by count(*) desc) as seqnum
          from @t
          group by description
         ) d
    group by (case when seqnum <= 4 then description else 'Other' end)
    order by min(seqnum);
    

    【讨论】:

    • 我收到“无效列名'cnt'的错误。我认为这是由于派生表的窗口函数中的“按cnt desc排序”。
    • 我想我明白了。我将“按 cnt 排序”更改为“按计数排序(*)
    • @jackstraw22 。 . .谢谢。
    【解决方案2】:

    使用窗口函数COUNT()

    with 
      cte as (
        select distinct
          description, 
          count(*) over (partition by description) counter
        from @t
      ),
      top3 as (select top 3 with ties * from cte order by counter desc)  
    select description, counter
    from (
      select description, counter, 1 ord from top3
      union all
      select distinct 'Others', count(*) over (), 2
      from @t
      where description not in (select description from top3)
    ) t
    order by ord, counter desc
    

    请参阅demo
    结果:

    > description | counter
    > :---------- | ------:
    > Nose        |       6
    > Digestive   |       5
    > Cardiac     |       4
    > Muscular    |       4
    > Others      |       3
    

    【讨论】:

      【解决方案3】:

      鉴于您似乎想要处理平局,请使用 rank() 而不是 row_number():

      select description
      , sum(cnt) as cnt
      from (
          select case
              when rank() over(order by count(*) desc) <= 3 then description
              else 'Other' end as description
          , count(*) as cnt
          from @t
          group by description
      )
      group by description
      

      【讨论】:

        猜你喜欢
        • 2018-12-17
        • 1970-01-01
        • 1970-01-01
        • 2019-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-24
        • 2020-02-18
        相关资源
        最近更新 更多