显示前三个值和所有其他值的总和

时间:2013-08-30 19:42:29

标签: sql sql-server

ORDER BY cnt DESC后我的结果是

fld1  cnt
 A     9
 E     8
 D     6
 C     2
 B     2
 F     1

我需要显示前3个,其余的要总结为'其他',如下所示:

fld1  cnt
A      9
E      8
D      6
other  5

编辑:

谢谢大家的意见。如果你看到实际的陈述,也许会有所帮助:

SELECT 
    CAST(u.FA AS VARCHAR(300)) AS FA,
    COUNT(*) AS Total,
    COUNT(CASE WHEN r.RT IN (1,11,12,17) THEN r.RT END) AS Jr,
    COUNT(CASE WHEN r.RT IN (3,4,13) THEN r.RT END) AS Bk,
    COUNT(CASE WHEN r.RT NOT IN (1,11,12,17,3,4,13) THEN r.RT END ) AS Other
FROM R r
    INNER JOIN DB..RTL rt
    ON r.RT = rt.RTID
    INNER JOIN U u
    ON r.UID = u.UID
WHERE rt.LC = 'en' 
GROUP BY CAST(u.FA AS VARCHAR(300))--FA is ntext
ORDER BY Total DESC

产生的结果有19条记录。我需要显示前5名并将其余部分总结为"其他FA"。我不想从选择中选择这种语句进行选择。我更喜欢一些SQL函数。也许ROW_NUMBER是个好主意,但我不知道在这种情况下如何应用它。

5 个答案:

答案 0 :(得分:3)

可能是这样的:

select top 3 fld1, cnt from mytable
union
select 'Z - Other', sum(cnt) from mytable
where fld1 not in (select top 3 fld1 from mytable order by fld1)
order by fld1

(已更新,包含订单)

答案 1 :(得分:2)

DECLARE @MyTable TABLE
(
    fld1 VARCHAR(50) NOT NULL,
    cnt INT NOT NULL
);
INSERT INTO @MyTable (fld1, cnt) 
VALUES 
('A', 9), ('E', 8), ('D', 6),
('C', 2), ('B', 2), ('F', 1);

SELECT  ISNULL(z.new_fld1,'other') AS new_fld1,
        SUM(z.cnt) AS sum_of_cnt
        --,MAX(z.sort_cryteria)
FROM
(
    SELECT  y.cnt, 
            -- I assume that `fld1` column is MANDATORY (NOT NULL) !
            CASE WHEN y.RowNum < 4 THEN fld1 ELSE NULL END AS new_fld1,
            CASE WHEN y.RowNum < 4 THEN y.RowNum ELSE 4 END AS sort_cryteria
    FROM
    (
        SELECT  *, ROW_NUMBER() OVER(ORDER BY x.cnt DESC) AS RowNum
        FROM    @MyTable x
    ) y
) z 
GROUP BY z.new_fld1
ORDER BY MAX(z.sort_cryteria);

结果:

new_fld1 sum_of_cnt  sort_cryteria
-------- ----------- -------------
A        9           1
E        8           2
D        6           3
NULL     5           4

答案 2 :(得分:2)

我认为最直接的方法是使用row_number()枚举行然后重新创建它们:

select (case when seqnum <= 3 then fld1 else 'Other' end) as fld1,
       sum(cnt) as cnt
from (select t.*, row_number() over (partition by fld1 order by cnt desc) as seqnum
      from t
     ) t
group by (case when seqnum <= 3 then fld1 else 'Other' end);

您实际上也可以将此作为原始聚合的一部分:

select (case when seqnum <= 3 then fld1 else 'Other' end) as fld1,
       sum(cnt) as cnt
from (select fld1, sum(...) as cnt,
             row_number() over (partition by fld1 order by sum(...) desc) as seqnum
      from t
      group by fld1
     ) t
group by (case when seqnum <= 3 then fld1 else 'Other' end);
编辑(基于修订后的问题):

select (case when seqnum <= 3 then FA else 'Other' end) as FA,
       sum(Total) as Total
from (SELECT CAST(u.FA AS VARCHAR(300)) AS FA,
             COUNT(*) AS Total,
             ROW_NUMBER() over (PARTITION BY CAST(u.FA AS VARCHAR(300)) order by COUNT(*) desc
                               ) as seqnum
      FROM R r
          INNER JOIN DB..RTL rt
          ON r.RT = rt.RTID
          INNER JOIN U u
          ON r.UID = u.UID
      WHERE rt.LC = 'en' 
      GROUP BY CAST(u.FA AS VARCHAR(300))--FA is ntext
     ) t
group by (case when seqnum <= 3 then FA else 'Other' end)
order by max(seqnum) desc;

最终order by按总计按升序保存记录。

答案 3 :(得分:0)

您可以尝试这样的事情:

select fld1,cnt from test
where cnt in(select top 3 cnt from test)
union
select 'Other', sum(cnt)from test
where cnt not in (select top 3 cnt from test)
order by cnt desc;

SQLFiddle

答案 4 :(得分:-2)

我不确定如何在SQLServer中使用“first”和skip子句 但在firebird中这有效,但我认为它可以修改为在SQLServer上运行

    select first 3 p.fld1,p.cnt from Table p
    union
    select t."others",sum(t.cnt )  from (
    select skip 3 'others' as "others",p.cnt from Table p
    ) as t
    group by "others"