经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » SQL语言 » 查看文章
SQL-去除最大值与最小值求均值的问题
来源:cnblogs  作者:业余砖家  时间:2023/8/7 9:14:49  对本文有异议
  • 背景

今天有同事问我一道关于数据库SQL的面试题,我刚开始随便给了一个思路,后来思索发现这个思路有漏洞,于是总结下来,仅供参考。

问题: 薪水表中是员工薪水的基本信息,包括雇员编号,和薪水,查询除去最高、最低薪水后的平均薪水。

  • 一、薪水表信息
  1. CREATE TABLE `salaries` (
  2. `emp_no` int NOT NULL,
  3. `salary` int NOT NULL
  4. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

测试数据如下:

  1. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10003, 6000);
  2. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10004, 6000);
  3. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10001, 6000);
  4. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10006, 6100);
  5. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10005, 6900);
  6. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (10008, 7100);
  7. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100010, 7400);
  8. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100013, 7500);
  9. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100014, 7500);
  10. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100015, 7688);
  11. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100018, 8000);
  12. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100020, 8100);
  13. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100028, 8200);
  14. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100026, 8400);
  15. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100035, 8500);
  16. INSERT INTO `salaries`(`emp_no`, `salary`) VALUES (100038, 8500);
  • 二、查询分析

思路1、最容易想到的方法,就是查询到薪水的最大值和最小值。然后从薪水中排除掉这两个,计算平均值即可。

  1. select avg(salary)
  2. from salaries
  3. where salary not in (
  4. (select min(salary) from salaries),
  5. (select max(salary) from salaries)
  6. ) ;

 

思路2、使用开窗函数Max()  Over() 和 Min()  Over() 求出最大值,然后排除掉这两个,再计算平均值。

  1. select
  2. avg(salary)
  3. from (
  4. select emp_no,salary, min(salary) over() min_sal, max(salary) over() max_sal from salaries
  5. ) x
  6. where salary not in (min_sal,max_sal) ;

 

思路3 、直接使用数学方法,平均值 = (求和-最大值-最小值)/ (总个数-2)

  1. select (sum(salary)-min(salary)-max(salary))/(count(*)-2)
  2. from salaries ;

 

思路4、使用一次row_number() over 窗口函数和count() over 函数,count窗口函数统计表中所有记录数,使用row_number窗口函数按照薪水升序排列,排序结果 = 1 即为最小值,排序结果 = count出的结果 即为最大值。 

  1. select
  2. avg(salary)
  3. from
  4. (
  5. select
  6. emp_no,
  7. salary,
  8. count(*) over() num ,
  9. row_number() over(order by salary asc) rn
  10. from salaries ) T
  11. where rn <> 1 and rn <> num ;

说明:

  1. count(*)over() 求总计数,
  2. count(*)over(order by A...) 递加求计数,
  3. count(*)over(partition by A...) 分组求计数,
  4. count(*)over(partition by A...order by b...) 分组递加求计数

查询看下这四个统计结果

 

思路5、使用两次row_number() over 窗口函数,一个按照薪水升序,一个按照薪水降序,过滤掉第一个即去掉最大值和最小值。

  1. select
  2. avg(salary)
  3. from
  4. (
  5. select
  6. emp_no,
  7. salary,
  8. row_number() over(order by salary desc) rn_desc,
  9. row_number() over(order by salary asc) rn_asc
  10. from salaries ) T
  11. where rn_desc > 1 and rn_asc > 1 ;

 

总结: 我们在执行这5个SQL语句后,会发现统计出的平均值不一样,原因就在于:薪水表中最高薪水的人和最低薪水的人都不止一个。

前2个思路会将所有最高薪水和最低薪水全部去除,求得平均值。然而,思路3、4、5都只是去除一个最高薪水和一个最低薪水,然后求平均值。所以才导致计算出的结果不一致。

 

原文链接:https://www.cnblogs.com/yeyuzhuanjia/p/17607965.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号