2

在我之后我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 是个好主意,但我不知道在这种情况下如何应用它。

4

5 回答 5

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

(更新以包括订购者)

于 2013-08-30T20:13:22.890 回答
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
于 2013-08-30T19:59:50.573 回答
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保持记录按总升序排列。

于 2013-08-30T20:20:24.883 回答
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

于 2013-08-30T20:27:12.917 回答
-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"
于 2013-08-30T19:58:06.063 回答