1789. Primary Department for Each Employee
这道题复杂的地方在于只有一个部门的人对应的flag也是N,因此在筛选的时候比较困难。
这里就要使用UNION,很多时候我都想不到这个,以后遇到这种不好使用CASE区分的情况,就可以考虑使用UNION,它会自动去除重复的行。
select employee_id, department_id from Employee group by employee_id having count(department_id) = 1 union select employee_id, department_id from Employee where primary_flag = 'Y' ;
或者这道题目也可以使用窗口函数:
参考:https://leetcode.cn/problems/primary-department-for-each-employee/solutions/2517404/chuang-kou-han-shu-1789que-ding-yuan-gon-oeq3
窗口函数可以在子查询中通过PARTITION BY employee_id对每个员工进行分区,并对每个分区内的记录数进行计数,这样我们就可以知道每个员工出现的次数。
首先写出答案:
SELECT employee_id, department_id FROM(SELECT employee_id, department_id, primary_flag, COUNT(*) OVER (PARTITION BY employee_id) count FROM Employee) sub WHERE count = 1 OR primary_flag = 'Y'
COUNT(*) OVER (PARTITION BY employee_id) count
: 这是一个窗口函数的使用。COUNT(*)
是计算每个窗口(由 PARTITION BY employee_id
定义)中的行数。具体来说,它会为每个 employee_id
分组计算相应的行数,并将结果作为一个名为 count
的新列返回。
很多人好奇这和GROUP BY之后再COUNT有什么区别呢,让我们来运行一下:
| employee_id | department_id | primary_flag | | ----------- | ------------- | ------------ | | 1 | 1 | N | | 2 | 1 | Y | | 2 | 2 | N | | 3 | 3 | N | | 4 | 2 | N | | 4 | 3 | Y | | 4 | 4 | N |
输入如上,使用窗口函数代码得到的输出如下:
SELECT employee_id, department_id, primary_flag, COUNT(*) OVER (PARTITION BY employee_id) count FROM Employee
| employee_id | department_id | primary_flag | count | | ----------- | ------------- | ------------ | ----- | | 1 | 1 | N | 1 | | 2 | 1 | Y | 2 | | 2 | 2 | N | 2 | | 3 | 3 | N | 1 | | 4 | 2 | N | 3 | | 4 | 3 | Y | 3 | | 4 | 4 | N | 3 |
使用GROUP BY以及COUNT得到的结果如下:
| employee_id | department_id | primary_flag | count | | ----------- | ------------- | ------------ | ----- | | 1 | 1 | N | 1 | | 2 | 1 | Y | 2 | | 3 | 3 | N | 1 | | 4 | 2 | N | 3 |
是不是一目了然,所以为了进行后续的筛选,我们得使用窗口函数的COUNT,否则分组后的COUNT可能会会丢失一些信息,影响我们后续的结果。