zoukankan      html  css  js  c++  java
  • Leetcode的SQL题解:185. 部门工资前三高的员工

    题目

    查询部门工资前三高的员工。

    我用的数据库是oracle。
    下面是数据表的信息。
    Employee表数据:

    | ID | NAME | Salary | DepartmentId |
    | -- | ---- | ------ | ------------ |
    |1 |	Joe	    |   85000	|   1   |
    |2 |	Henry	|	80000	|	2	|
    |3 |	Sam	    |	60000	|	2	|
    |4 |	Max	    |	90000	|	1	|
    |5 |	Janet	|	69000	|	1	|
    |6 |	Randy	|	85000	|	1	|
    |7 |	Will	|	70000	|	1	|
    |8 |	edav	|	50000	|	2	|
    |9 |	easonv	|	40000	|	2	|
    

    8、9行为我自行添加,为了更清晰展示查询结果。

    创建表

    Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id 。

    create table Employee (
      Id number(5),
      Name varchar2(10) ,
      Salary number(5),
      DepartmentId number(5)
    );
    

    Department 表包含公司所有部门的信息。

    create table Department  (
      Id number(5),
      Name varchar2(10) 
    );
    

    插入数据Employee,脚本如下

    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('1', 'Joe', '85000', '1');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('2', 'Henry', '80000', '2');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('3', 'Sam', '60000', null);
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('4', 'Max', '90000', '1');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('5', 'Janet', '69000', '1');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('6', 'Randy', '85000', '1');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('7', 'Will', '70000', '1');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('8', 'eda', '50000', '2');
    
    insert into Employee (ID, NAME, SALARY, DEPARTMENTID)
    values ('9', 'eason', '40000', '2');
    

    插入数据Department,脚本如下

    insert into Department (ID, NAME)
    values ('1', 'IT');
    
    insert into Department (ID, NAME)
    values ('2', 'Sales');
    

    查询

    以下使用四种SQL语句查出的结果,前两个是用oracle特有函数,后两个是标准SQL92写法。

    你觉得哪个对?哪个性能高?

    函数1 ROW_NUMBER

    select Department,Employee,Salary
     from (select (ROW_NUMBER()
                   over(PARTITION by t1.departmentid order by Salary desc)) lev,
                  t2.name Department,
                  t1.name Employee,
                  t1.Salary Salary
             from Employee t1, Department t2
            where t1.departmentid = t2.id) A
    where lev <= 3;
    

    函数2 dense_rank

    select D.Name Department, E.Name Employee, E.Salary Salary
    	from (select Name,
    														Salary,
    														DepartmentId,
    														dense_rank() over(partition by DepartmentId order by Salary desc) Trank
    									from Employee) E
    right join Department D
    			on E.DepartmentId = D.id
    where Trank <= 3;
    

    通用写法1

    select d.name as Department, e.name as Employee, e.salary as Salary
      from employee  e
     inner join department  d
        on e.DepartmentId = d.id
     where  (select count(distinct salary)
              from employee
             where salary > e.salary
               and departmentid = e.DepartmentId) < 3
     order by e.departmentid, Salary desc;
    

    通用写法2

    SELECT t3.name Department, t2.name Employee, t2.salary Salary
    	FROM Employee t2, Department t3
    WHERE t2.id NOT IN (SELECT b.id
    						FROM Employee a, Employee b
    						WHERE a.DepartmentId = b.DepartmentId
    								AND a.salary > b.salary
    								GROUP BY b.id
    								HAVING COUNT(*) >= 3)
    		AND t2.DepartmentId = t3.id
    ORDER BY Department, t2.salary DESC;
    

    吐槽

    感兴趣的同学可以自己跑下。

    我个人觉得所谓官方答案是有问题的。

    官方题解如下,mysql版本:

    SELECT d.Name AS 'Department', e1.Name AS 'Employee', e1.Salary
    	FROM Employee e1
    	JOIN Department d
    			ON e1.DepartmentId = d.Id
        WHERE 3 > (SELECT COUNT(DISTINCT e2.Salary)
    				FROM Employee e2
    				WHERE e2.Salary > e1.Salary
    			AND e1.DepartmentId = e2.DepartmentId);
    

    改写成oracle版,加上排序:

    SELECT d.Name Department, e1.Name Employee, e1.Salary
    	FROM Employee e1
    	JOIN Department d
    			ON e1.DepartmentId = d.Id
        WHERE 3 > (SELECT COUNT(DISTINCT e2.Salary)
    				FROM Employee e2
    				WHERE e2.Salary > e1.Salary
    			AND e1.DepartmentId = e2.DepartmentId)
    	 order by d.id,salary desc
    

    查出来的数据是与通用写法1一样的,
    两个同样的85000的数据

    |序号| Department | Employee | Salary |
    |--- | ---- | ------- | ------------ |
    |1 |	IT  |	Max   |	90000
    |2 |	IT  | 	Randy |	85000
    |3 |	IT  |	Joe   |	85000
    |4 |	IT  |	Will  |	70000
    |5 |	Sales |	Henry |	80000
    |6 |	Sales |	Sam   |	60000
    |7 |	Sales |	eda|	50000
    

    这个题目出的歧义太大,如果是在考试中,应该是查出前三名、前四名的都对。

    个人认为应该查出前三名应该是不包含70000这条数据的,就算是并列第二,那么就应该没有第三了,高校排名不也是这样吗?

    所以私以为正确答案应该是查出这样的数据

    |序号| Department | Employee | Salary |
    |--- | ---- | ------- | ------------ |
    |1 |	IT  |	Max   |	90000
    |2 |	IT  | 	Randy |	85000
    |3 |	IT  |	Joe   |	85000
    |4 |	Sales |	Henry |	80000
    |5 |	Sales |	Sam   |	60000
    |6 |	Sales |	eda|	50000
    

    那么,我写的四条语句中,应该是函数1及通用写法2可以满足这个条件。


    我的公众号

  • 相关阅读:
    从Unity3D编译器升级聊起Mono
    RxJava系列6(从微观角度解读RxJava源码)
    RxJava系列5(组合操作符)
    RxJava系列4(过滤操作符)
    RxJava系列3(转换操作符)
    RxJava系列2(基本概念及使用介绍)
    RxJava系列1(简介)
    给 Android 开发者的 RxJava 详解
    深入浅出RxJava就这一篇就够了
    android非法字符的判定、表情符号的判定
  • 原文地址:https://www.cnblogs.com/yaomaomao/p/11133437.html
Copyright © 2011-2022 走看看