使用 GROUP BY 时如何创建“其他”组?

WoJ*_*WoJ 3 sql sqlite

摘要:我对数据进行了分组、计数和按计数排序。我想只保留前 X 行,并将其他行累积为称为“其他”的行

以下数据可在 DB Fiddle 获取

CREATE TABLE cities (name TEXT);
INSERT INTO cities(name) VALUES ('paris'), ('paris'), ( 'london'), ( 'london'), ( 'london'), ( 'london'), ( 'rome'), ( 'madrid');

SELECT name, COUNT(name) AS count FROM cities
GROUP BY name
ORDER BY count DESC
LIMIT 2
Run Code Online (Sandbox Code Playgroud)

上面的代码生成前两个最常出现的城市(条目数量最多的城市):

| name   | count |
| ------ | ----- |
| london | 4     |
| paris  | 2     |
Run Code Online (Sandbox Code Playgroud)

我想实现的是

| name   | count |
| ------ | ----- |
| london | 4     |
| paris  | 2     |
| other  | 2     |
Run Code Online (Sandbox Code Playgroud)

其中所有剩余行('rome''madrid'我的情况下)都在 下分组在一起other

我不太了解 SQL,但在伪代码中我正在考虑类似的事情

| name   | count |
| ------ | ----- |
| london | 4     |
| paris  | 2     |
Run Code Online (Sandbox Code Playgroud)

这可以在一次传递中实现吗?作为解决方法,我将有相同的查询,但以相反的方式排序,并限制为“行数 - 前 2 个”(所以我认为总共 3 个查询)。

(令我惊讶的是,以前没有人问过这个问题,但找不到匹配项)

ahm*_*med 6

一种选择是在 row_number 函数上使用带有 case 表达式的另一级别聚合:

WITH T AS
(
  SELECT
     name, 
     COUNT(name) AS count,
     ROW_NUMBER() OVER (ORDER BY COUNT(name) DESC) AS rn 
  FROM cities
  GROUP BY name
  ORDER BY count DESC
)
SELECT 
   CASE 
     WHEN rn IN (1, 2) 
     THEN name 
     ELSE 'Others' 
   END AS name,
   SUM(count) AS count
FROM T
GROUP BY 1
ORDER BY count DESC
Run Code Online (Sandbox Code Playgroud)

为了确保“其他”出现在结果集中的最后,您可以ORDER BY CASE WHEN rn IN (1, 2) THEN 1 ELSE 2 END, count DESC

演示