【问题标题】:Get employees who received a raise in 2 consecutive years获取连续2年获得加薪的员工
【发布时间】:2022-11-14 20:30:09
【问题描述】:

我正在尝试获取连续 2 年获得加薪的员工,在这种情况下,员工 1000 是正确答案。

这是我尝试过的数据和sql。

EID SALARY YEAR
1000 10,000 2016
1000 7,500 2015
1000 6,000 2014
1001 8,000 2016
1001 7,500 2015
1002 7,500 2016
1002 7,500 2015
1002 5,000 2014
1003 6,000 2016
1003 7,000 2015
1003 5,000 2014

我使用了以下代码,但是它仅按 EID 获取行号,而不是去年和今年的计算,我需要找到连续 2 年加薪的员工。

output

select * , 
       row_number() over(partition by eid order by salary and year desc)as rn 
from gs;

【问题讨论】:

  • 哪个版本的 MySQL? MySQL 8+ 具有 MySQL 5.x 中不存在的功能

标签: mysql sql


【解决方案1】:

您可以使用LEAD 窗口函数来计算工资的两个连续前值。然后您可以使用salary1 < salary2 < salary3 检查有多少员工至少有一行。

SELECT DISTINCT 
    eid
FROM (
    SELECT
        eid,
        year,
        salary,
        (LEAD(salary, 1) OVER(PARTITION BY eid ORDER BY year DESC)) AS prev_salary1,
        (LEAD(salary, 2) OVER(PARTITION BY eid ORDER BY year DESC)) AS prev_salary2
    FROM 
        employees
    ) consecutive3
WHERE 
    salary > prev_salary1
AND     
    prev_salary1 > prev_salary2

假设没有缺失的年份没有记录受抚养人的工资。

这是小提琴:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=8c0d8a1deec8e77bb32a173656c3e386


编辑:详细解释

让我们以詹妮弗为例,她工作了五年,拿到了这些薪水:

  • 2018 -> 65000
  • 2017 -> 55000
  • 2016 -> 50000

她是被选上的候选人,因为她的薪水连续提高了三倍。

1.LEAD(salary, 1) OVER(PARTITION BY eid ORDER BY year DESC)

允许您获取“Y”年的薪水和“Y-1”年的薪水:

(“年份”->“薪水”,“previous_salary”)

  • 2018 -> 65000 , 55000
  • 2017 -> 55000 , 50000
  • 2016 -> 50000,空

2.LEAD(salary, 2) OVER(PARTITION BY eid ORDER BY year DESC)

允许您获取“Y”年的薪水和“Y-1”年的薪水:

(“年”->“薪水”,“previous_salary”,“previous_salary_by_2_years”)

  • 2018 -> 65000 , 55000 , 50000
  • 2017 -> 55000 , 50000 , 空
  • 2016 -> 50000,空,空

3.WHERE salary > prev_salary1 AND prev_salary1 > prev_salary2

对员工进行一些过滤

  • 第三年的薪水高于第二年的薪水 (salary > prev_salary1)
  • 他们第二年的薪水高于第一年的薪水 (prev_salary1 > prev_salary2)

【讨论】:

  • 你能解释一下代码吗?
  • 将两次加薪返回员工,不一定是连续两年。 300->400->400->500 将满足此查询的条件。
  • 非空检查是多余的。如果该值为空,则大于检查不能为真。
  • 如果 EID 消失一年并返回更高的薪水,则包括边缘情况。 (2013,$5000), (2014,$6000), (2016,$9000) 将返回 true,但 2015 年没有记录。我认为不应包括 eid,但确实如此。但总体不错。
  • 确切地说:它写在@xQbert 的假设中。包含该细节的解决方案会比这个复杂得多,但如果我是一家公司,我的员工离开后又回来,我猜我不会为他们分配相同的员工 ID……我将把它留给写问题的人来决定以防万一。不管怎么说,多谢拉!
【解决方案2】:

我知道这已经得到解答,但这是我使用滞后函数确定是否比前一年增加并运行两次的结果。

SELECT *
FROM (
    SELECT
        t2.*,
        LAG(increase) over (partition by eid order by year) AS increaseNextYear
    FROM (
        SELECT
            t1.*,
            COALESCE(salary - LAG(salary) over (partition by eid order by year), 0) > 0 AS increase
        FROM tbl_test t1
    ) as t2
) t3 where increase AND increaseNextYear

【讨论】:

  • Lag 采用一个可选参数来指示要查看的行数。使用它你可以在同一个查询中滞后两次,不需要子查询。 dev.mysql.com/doc/refman/8.0/en/…
  • 很好,我会记住那个!
【解决方案3】:
with
  dates as
(
  select
    a.*,
    dense_rank() OVER (
      partition by eid
          order by year desc, salary
      )
        as rn, 
    case
      when 
        lead(salary,2)over(partition  by eid order by year, salary)
        >
        lead(salary,1)over(partition by eid order by year, salary)
      and  
        lead(salary,1)over(partition by eid order by year, salary)
        >
        salary
      then
        1
      else
        0
    end
      as flag
  from
    employees a
)
select
  eid
from
  dates
where
      rn   = 3
  and flag = 1

【讨论】:

  • @MatBailie 非常感谢您编辑代码。我尝试美化代码,但我不知道如何。谢谢
  • 行号检查有问题。这仅适用于最近两年加薪的情况。序列300->400->500->500 呢?条件仅在第 4 行中成立。
【解决方案4】:

不是一个漂亮的查询,而是直截了当的:查找在上一年的薪水较低且前一年的薪水更低的一年的员工。使用LAG 更优雅,但我想我会把它扔进去,只是为了展示一个替代方案。

select *
from employee
where exists
(
  select null
  from gs
  where gs.eid = employee.id
  and exists
  (
    select null
    from gs prev
    where prev.eid = gs.eid
    and prev.year = gs.year - 1
    and prev.salary < gs.salary
    and exists
    (
      select null
      from gs prevprev
      where prevprev.eid = prev.eid
      and prevprev.year = prev.year - 1
      and prevprev.salary < prev.salary
    )
  )
);

加入同样的事情:

select *
from employee
where exists
(
  select null
  from gs
  join gs prev on prev.eid = gs.eid
              and prev.year = gs.year - 1
              and prev.salary < gs.salary
  join gs prevprev on prevprev.eid = prev.eid
                  and prevprev.year = prev.year - 1
                  and prevprev.salary < prev.salary
  where gs.eid = employee.id
);

【讨论】:

    【解决方案5】:

    对于 8.0 之前的版本(我的是 5.7),缺少新版本的尖端功能,我尝试了一个程序来完成这项工作。首先,获得所有开斋节的工资记录不少于三年,这是连续奖金的最低要求。剩下的就是使用 eid 池中的游标来获取和比较。结果存储在临时表 t 中。

    delimiter //
    drop procedure if exists lucky_emp//
    create procedure lucky_emp()
    begin
    declare old_eid int default 0;
    declare old_salary int;
    declare new_eid int ;
    declare new_salary int;
    declare bonus_year int;
    declare fin bool default false;
    declare c cursor for select eid,salary from salary where eid in(select eid from salary group by eid having count(eid)>=3) order by eid,year;
    declare continue handler for not found set fin=true;
    drop temporary table if exists t ;
    create temporary table t (t_eid int);
    open c;
    lp:loop
        fetch c into new_eid ,new_salary;
        if fin=true then
            leave lp;
        end if;
        if new_eid !=old_eid then
            set old_eid=new_eid,old_salary=0,bonus_year=0;
        end if;
        if new_salary> old_salary then
            set bonus_year=bonus_year+1,old_salary=new_salary;
        else 
            set bonus_year=0;
        end if;
    
        if bonus_year=3 and new_eid not in(select t_eid from t) then
            insert t values(new_eid);
        end if;
    
    end loop lp;
    
    end// 
    delimiter ;
    select * from t ;
    

    【讨论】:

      【解决方案6】:
      Select a.*, b.prev_sal1, b.prev_sal2
      from employees a
      join (
           Select eid ,year,
           lag(salary,1) over (partition by eid order by year) as prev_sal1,
           lag(salary,2) over (partition by eid order by year) as prev_sal2
           from employees ) b
      on a.eid=b.eid
      and a.year = b.year
      where salary>prev_sal1 and prev_sal1>prev_sal2
      

      小提琴:https://dbfiddle.uk/rfGv31zM

      【讨论】:

        猜你喜欢
        • 2019-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-25
        • 2021-11-24
        • 1970-01-01
        • 1970-01-01
        • 2011-11-17
        相关资源
        最近更新 更多