SQL 找出元组的平均数量(既不是最大值也不是最小值)
SQL find average number of tuples (neither max nor min)
假设我有两个表 PEOPLE
和 WORK
。我想找到所有 work
的最大和最小数量 people
.
示例:
PEOPLE
ID NAME WORK
1 Mark Programmer
2 Sonia Singer
3 Jack Programmer
4 Mirco Welder
5 Jeff Welder
6 Tom Welder
WORK
ID WORK
1 Programmer
2 Singer
3 Welder
结果应该是:
Programmer
这样的MySQL query
怎么写??
谢谢大家
你必须认为这是一种脑筋急转弯。你肯定会找到一组 3 个元素:
1 Maximum represented by Welder job done by Mirco, Jeff and Tom
2 Medium represented by Programmer done by Mark and Jack who is the Job I would like to find
3 Minimum represented by Singer done only from Sonia
谢谢
此查询适用于支持 CTE 的 SQL 版本(例如 SQL Server、PostgreSQL、MySQL 8+):
WITH counts AS
(SELECT WORK, COUNT(*) AS num
FROM people
GROUP BY WORK),
minmax AS
(SELECT MIN(num) AS min, MAX(num) AS max
FROM counts)
SELECT WORK
FROM counts c
JOIN minmax m ON c.num != m.min AND c.num != m.max
输出:
WORK
Programmer
这是一种使用 window 函数的方法:
- 首先使用聚合查询计算每个作品的人数
- 然后按人数升序和降序排列作品
- 最后,过滤掉顶部和底部的记录
查询:
SELECT work
FROM (
SELECT
work,
ROW_NUMBER() OVER(ORDER BY cnt) rn_asc,
ROW_NUMBER() OVER(ORDER BY cnt DESC) rn_desc
FROM (
SELECT work, COUNT(*) cnt FROM people GROUP BY work
) x
) x WHERE rn_asc != 1 AND rn_desc != 1
| work |
| ---------- |
| Programmer |
注意:就此而言,您无需查询 work
table 即可获得预期结果,因为所有相关信息都可在 people
.
另一种方式。使用子查询查找最小和最大计数,并将其与每个工作的计数连接到另一个子查询。然后左连接并消除匹配最小或最大计数的行。
declare @people table (id int, name varchar(20), work varchar(50))
insert into @people
values (1, 'Mark' , 'Programmer'),
(2, 'Sonia' ,'Singer'),
(3, 'Jack', 'Programmer'),
(4, 'Mirco', 'Welder'),
(5, 'Jeff', 'Welder'),
(6, 'Tom', 'Welder')
select a.work
from ( -- A subquery that returns the count of each work
select work, count(*) cnt
from @people
group by work
) a
left outer join ( -- a subquery that returns the min and max counts
select min(cnt) mincount, max(cnt) maxcount
from (
select count(*) cnt
from @people
group by work
) b
) c
on a.cnt = c.mincount
or a.cnt = c.maxcount
where c.mincount is null
如果您想在没有 window 功能的情况下执行此操作:
select w.*
from work w
where w.work not in (select p.work
from people p
group by p.work
order by count(*) asc
fetch first 1 row only
) and
w.work not in (select p.work
from people p
group by p.work
order by count(*) desc
fetch first 1 row only
);
请注意,如果出现重复,这只会考虑一行 minimum/maximum,因此可以返回并列。
假设我有两个表 PEOPLE
和 WORK
。我想找到所有 work
的最大和最小数量 people
.
示例:
PEOPLE
ID NAME WORK
1 Mark Programmer
2 Sonia Singer
3 Jack Programmer
4 Mirco Welder
5 Jeff Welder
6 Tom Welder
WORK
ID WORK
1 Programmer
2 Singer
3 Welder
结果应该是:
Programmer
这样的MySQL query
怎么写??
谢谢大家
你必须认为这是一种脑筋急转弯。你肯定会找到一组 3 个元素:
1 Maximum represented by Welder job done by Mirco, Jeff and Tom
2 Medium represented by Programmer done by Mark and Jack who is the Job I would like to find
3 Minimum represented by Singer done only from Sonia
谢谢
此查询适用于支持 CTE 的 SQL 版本(例如 SQL Server、PostgreSQL、MySQL 8+):
WITH counts AS
(SELECT WORK, COUNT(*) AS num
FROM people
GROUP BY WORK),
minmax AS
(SELECT MIN(num) AS min, MAX(num) AS max
FROM counts)
SELECT WORK
FROM counts c
JOIN minmax m ON c.num != m.min AND c.num != m.max
输出:
WORK
Programmer
这是一种使用 window 函数的方法:
- 首先使用聚合查询计算每个作品的人数
- 然后按人数升序和降序排列作品
- 最后,过滤掉顶部和底部的记录
查询:
SELECT work
FROM (
SELECT
work,
ROW_NUMBER() OVER(ORDER BY cnt) rn_asc,
ROW_NUMBER() OVER(ORDER BY cnt DESC) rn_desc
FROM (
SELECT work, COUNT(*) cnt FROM people GROUP BY work
) x
) x WHERE rn_asc != 1 AND rn_desc != 1
| work |
| ---------- |
| Programmer |
注意:就此而言,您无需查询 work
table 即可获得预期结果,因为所有相关信息都可在 people
.
另一种方式。使用子查询查找最小和最大计数,并将其与每个工作的计数连接到另一个子查询。然后左连接并消除匹配最小或最大计数的行。
declare @people table (id int, name varchar(20), work varchar(50))
insert into @people
values (1, 'Mark' , 'Programmer'),
(2, 'Sonia' ,'Singer'),
(3, 'Jack', 'Programmer'),
(4, 'Mirco', 'Welder'),
(5, 'Jeff', 'Welder'),
(6, 'Tom', 'Welder')
select a.work
from ( -- A subquery that returns the count of each work
select work, count(*) cnt
from @people
group by work
) a
left outer join ( -- a subquery that returns the min and max counts
select min(cnt) mincount, max(cnt) maxcount
from (
select count(*) cnt
from @people
group by work
) b
) c
on a.cnt = c.mincount
or a.cnt = c.maxcount
where c.mincount is null
如果您想在没有 window 功能的情况下执行此操作:
select w.*
from work w
where w.work not in (select p.work
from people p
group by p.work
order by count(*) asc
fetch first 1 row only
) and
w.work not in (select p.work
from people p
group by p.work
order by count(*) desc
fetch first 1 row only
);
请注意,如果出现重复,这只会考虑一行 minimum/maximum,因此可以返回并列。