如果按子句分组,如何在 mysql 中获得中位数?
How to get median in mysql if group by clause?
我的 mysql 版本是 8.+.
Table结构:
CREATE TABLE `loss` (
`date` date DEFAULT NULL,
`circle` varchar(100) DEFAULT NULL,
`district` varchar(100) DEFAULT NULL,
`kpi_1` int(11) DEFAULT NULL,
`kpi_2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
tableloss
的数据:
insert into `loss`(`date`,`circle`,`district`,`kpi_1`,`kpi_2`) values
('2020-09-20','101','delhi',90,100),
('2020-09-20','102','Punjab',80,10),
('2020-09-20','104','delhi',90,90),
('2020-09-20','104','New Delhi',20,10),
('2020-09-20','104','Punjab',45,23),
('2020-09-20','104','New Delhi',4,13),
('2020-09-20','104','New Delhi',7,150),
('2020-09-20','104','New Delhi',80,40),
('2020-09-20','104','New Delhi',80,50),
('2020-09-20','104','New Delhi',NULL,NULL);
查询:
select date,circle,district,count(*) as total_rows,sum(kpi_1),sum(kpi_2) from loss
group by date,circle,distrcit
我可以获得所有聚合,但如何找到中位数?
不幸的是,MySQL 没有聚合中值函数或 the-like - 甚至没有像 MariaDB 中那样的 window 函数。
使用 window 函数的一种解决方法是:
select date, circle, district, count(*) cnt, sum(kpi_1) sum_kpi1, sum(kpi_2) sum_kpi2,
avg(case when rn1 in (floor((cnt + 1)/2), floor((cnt + 2)/2)) then kpi1 end) media_kpi1,
avg(case when rn2 in (floor((cnt + 1)/2), floor((cnt + 2)/2)) then kpi2 end) media_kpi2
from (
select l.*,
row_number() over(partition by date, circle, district order by kpi1) rn1,
row_number() over(partition by date, circle, district order by kpi2) rn2,
count(*) over(partition by date, circle, district) cnt
from loss
) l
group by date, circle, district
假设您想要按日期、圈子和地区汇总记录,如您的原始查询中所示。如果您想要另一组列,则可以同时更改 group by
子句和 window 函数的 partition
。
我的 mysql 版本是 8.+.
Table结构:
CREATE TABLE `loss` (
`date` date DEFAULT NULL,
`circle` varchar(100) DEFAULT NULL,
`district` varchar(100) DEFAULT NULL,
`kpi_1` int(11) DEFAULT NULL,
`kpi_2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
tableloss
的数据:
insert into `loss`(`date`,`circle`,`district`,`kpi_1`,`kpi_2`) values
('2020-09-20','101','delhi',90,100),
('2020-09-20','102','Punjab',80,10),
('2020-09-20','104','delhi',90,90),
('2020-09-20','104','New Delhi',20,10),
('2020-09-20','104','Punjab',45,23),
('2020-09-20','104','New Delhi',4,13),
('2020-09-20','104','New Delhi',7,150),
('2020-09-20','104','New Delhi',80,40),
('2020-09-20','104','New Delhi',80,50),
('2020-09-20','104','New Delhi',NULL,NULL);
查询:
select date,circle,district,count(*) as total_rows,sum(kpi_1),sum(kpi_2) from loss
group by date,circle,distrcit
我可以获得所有聚合,但如何找到中位数?
不幸的是,MySQL 没有聚合中值函数或 the-like - 甚至没有像 MariaDB 中那样的 window 函数。
使用 window 函数的一种解决方法是:
select date, circle, district, count(*) cnt, sum(kpi_1) sum_kpi1, sum(kpi_2) sum_kpi2,
avg(case when rn1 in (floor((cnt + 1)/2), floor((cnt + 2)/2)) then kpi1 end) media_kpi1,
avg(case when rn2 in (floor((cnt + 1)/2), floor((cnt + 2)/2)) then kpi2 end) media_kpi2
from (
select l.*,
row_number() over(partition by date, circle, district order by kpi1) rn1,
row_number() over(partition by date, circle, district order by kpi2) rn2,
count(*) over(partition by date, circle, district) cnt
from loss
) l
group by date, circle, district
假设您想要按日期、圈子和地区汇总记录,如您的原始查询中所示。如果您想要另一组列,则可以同时更改 group by
子句和 window 函数的 partition
。