SQL — 从 GROUP BY 中取前 3 个值
SQL — take Top 3 values from GROUP BY
Fiddle: https://www.db-fiddle.com/f/9F7XPiGtuQAYXQ99HfNJGN/3
CREATE TABLE table_1 (
`country` VARCHAR(2),
`category` VARCHAR(2),
`cnt` INT
);
INSERT INTO table_1
(`country`, `category`, `cnt`)
VALUES
('US', 'AA', 20),
('US', 'BB', 15),
('US', 'CC', 25),
('US', 'DD', 30),
('FR', 'AA', 10),
('FR', 'BB', 5),
('FR', 'CC', 50),
('FR', 'DD', 60);
这是数据:
| country | category | cnt |
| ------- | -------- | --- |
| FR | DD | 60 |
| FR | CC | 50 |
| FR | AA | 10 |
| FR | BB | 5 |
| US | DD | 30 |
| US | CC | 25 |
| US | AA | 20 |
| US | BB | 15 |
我想获取每个国家/地区的前 3 行(前 3 个类别),按 cnt 列排序。例如,我想要:
| country | category | cnt |
| ------- | -------- | --- |
| FR | DD | 60 |
| FR | CC | 50 |
| FR | AA | 10 |
| US | DD | 30 |
| US | CC | 25 |
| US | AA | 20 |
table 尚未由 cnt 订购。我尝试做 LIMIT 3 或 TOP 3,但它并没有像我 want/gives 我整体排名前 3,但不是每个国家/地区。
您可以使用 row_number()
:
select t.*
from (select t.*, row_number() over (partition by country order by cnt desc) as seqnum
from t
) t
where seqnum <= 3;
您可以使用 dense_rank()
得到您的结果
select
*
from
(
select
*,
dense_rank() over (partition by country order by cnt desc) as rn
from yourTable
) subq
where rn <= 3
请使用以下查询,
select country, category, cnt from
(select country, category, cnt, row_number() over(partition by country order by cnt
desc) as rnk from table_1) qry
where rnk between 1 and 3;
演示:
我认为这里可以使用另一个概念,很高兴知道它。
可以使用max
和max_by
函数,并使用两个函数得到的附加参数n
,参数指向return n 值。参见 docs。
因此您的查询如下所示:
SELECT country, max(cnt,3) top3_cnt, max_by(category,cnt,3) top3_category
FROM table_1
GROUP BY country
-------
Results:
country top3_cnt top3_category
FR [60, 50, 10] [DD, CC, AA]
US [30, 25, 20] [DD, CC, AA]
顺便说一句,我喜欢使用 WITH
使用命名表创建测试数据。而不是真正创建表和插入数据。
因此对于此查询,您可以将其用于测试目的:
WITH table_1 (country,category,cnt) AS (
SELECT * FROM (VALUES
('US', 'AA', 20),
('US', 'BB', 15),
('US', 'CC', 25),
('US', 'DD', 30),
('FR', 'AA', 10),
('FR', 'BB', 5),
('FR', 'CC', 50),
('FR', 'DD', 60) ))
Fiddle: https://www.db-fiddle.com/f/9F7XPiGtuQAYXQ99HfNJGN/3
CREATE TABLE table_1 (
`country` VARCHAR(2),
`category` VARCHAR(2),
`cnt` INT
);
INSERT INTO table_1
(`country`, `category`, `cnt`)
VALUES
('US', 'AA', 20),
('US', 'BB', 15),
('US', 'CC', 25),
('US', 'DD', 30),
('FR', 'AA', 10),
('FR', 'BB', 5),
('FR', 'CC', 50),
('FR', 'DD', 60);
这是数据:
| country | category | cnt |
| ------- | -------- | --- |
| FR | DD | 60 |
| FR | CC | 50 |
| FR | AA | 10 |
| FR | BB | 5 |
| US | DD | 30 |
| US | CC | 25 |
| US | AA | 20 |
| US | BB | 15 |
我想获取每个国家/地区的前 3 行(前 3 个类别),按 cnt 列排序。例如,我想要:
| country | category | cnt |
| ------- | -------- | --- |
| FR | DD | 60 |
| FR | CC | 50 |
| FR | AA | 10 |
| US | DD | 30 |
| US | CC | 25 |
| US | AA | 20 |
table 尚未由 cnt 订购。我尝试做 LIMIT 3 或 TOP 3,但它并没有像我 want/gives 我整体排名前 3,但不是每个国家/地区。
您可以使用 row_number()
:
select t.*
from (select t.*, row_number() over (partition by country order by cnt desc) as seqnum
from t
) t
where seqnum <= 3;
您可以使用 dense_rank()
select
*
from
(
select
*,
dense_rank() over (partition by country order by cnt desc) as rn
from yourTable
) subq
where rn <= 3
请使用以下查询,
select country, category, cnt from
(select country, category, cnt, row_number() over(partition by country order by cnt
desc) as rnk from table_1) qry
where rnk between 1 and 3;
演示:
我认为这里可以使用另一个概念,很高兴知道它。
可以使用max
和max_by
函数,并使用两个函数得到的附加参数n
,参数指向return n 值。参见 docs。
因此您的查询如下所示:
SELECT country, max(cnt,3) top3_cnt, max_by(category,cnt,3) top3_category
FROM table_1
GROUP BY country
-------
Results:
country top3_cnt top3_category
FR [60, 50, 10] [DD, CC, AA]
US [30, 25, 20] [DD, CC, AA]
顺便说一句,我喜欢使用 WITH
使用命名表创建测试数据。而不是真正创建表和插入数据。
因此对于此查询,您可以将其用于测试目的:
WITH table_1 (country,category,cnt) AS (
SELECT * FROM (VALUES
('US', 'AA', 20),
('US', 'BB', 15),
('US', 'CC', 25),
('US', 'DD', 30),
('FR', 'AA', 10),
('FR', 'BB', 5),
('FR', 'CC', 50),
('FR', 'DD', 60) ))