按行检测列更改

Detect column change by row

首先,我确实搜索过类似的代码,但没有找到合适的。

我想要做的是显示每个员工的 employee_type_id 变化时的行,列出 employee_iddate from and last date_to for the coresponding Employee ID .

我试过分区和滞后功能,但我没能解决这个问题。

感谢任何帮助。

我有这个:

employee_id   Date_From               Date_To                 EMPLOYEE_TYPE_ID
----------- ----------------------- ----------------------- ----------------
11223344      2016-11-07 00:00:00.000 2016-12-11 00:00:00.000 1
11223344      2016-12-12 00:00:00.000 2016-12-31 00:00:00.000 1
11223344      2017-01-01 00:00:00.000 2017-04-28 00:00:00.000 38
11223344      2017-04-29 00:00:00.000 2017-06-30 00:00:00.000 38
11223344      2017-07-01 00:00:00.000 2017-11-30 00:00:00.000 1
11223344      2017-12-01 00:00:00.000 2018-01-04 00:00:00.000 38
...
22233344      2012-06-01 00:00:00.000 2012-10-31 00:00:00.000 1
22233344      2012-11-01 00:00:00.000 2014-02-28 00:00:00.000 1
22233344      2017-12-01 00:00:00.000 2018-01-04 00:00:00.000 39
22233344      2018-01-05 00:00:00.000 2018-03-09 00:00:00.000 2

这就是我想要实现的目标:

employee_id   Date_From              EMPLOYEE_TYPE_ID
----------- -----------------------  ----------------
11223344      2016-11-07 00:00:00.000 2016-12-31 00:00:00.000 1
11223344      2017-01-01 00:00:00.000 2017-06-30 00:00:00.000 38
11223344      2017-07-01 00:00:00.000 2017-11-30 00:00:00.000 1
11223344      2017-12-01 00:00:00.000 2018-01-04 00:00:00.000 38
...
22233344      2012-06-01 00:00:00.000 2014-02-28 00:00:00.000 1
22233344      2017-12-01 00:00:00.000 2018-01-04 00:00:00.000 39
22233344      2018-01-05 00:00:00.000 2018-03-09 00:00:00.000 2

正如 Time Biegeleisen 评论的那样,这是典型的间隙和孤岛问题。您想要将具有相同 employee_idemployee_type_id.

的 "adjacent" 行组合在一起

这是使用 window 函数解决它的一种方法:

select
    employee_id,
    min(date_from) date_from,
    max(date_to) date_to,
    employee_type_id
from (
    select
        t.*,
        row_number() over(partition by employee_id order by date_from) rn1,
        row_number() over(partition by employee_id, employee_type_id order by date_from) rn2
    from mytable t
) t
group by employee_id, employee_type_id, rn1 - rn2

内部查询在两个不同的分区(每个员工和每个员工 类型)上对记录进行排名。当行号之间的差异发生变化时,一个新的岛开始(您可以 运行 独立子查询并查看它产生的结果)。然后,外部查询只是按组聚合。

如果没有间隙,您也可以使用 lag()/lead() 和 window 函数执行此操作:

select employee_id, EMPLOYEE_TYPE_ID,
       date_from,
       coalesce(dateadd(day, -1, lead(date_from) over (partition by emplyee_id order by date_from),
                max_date_to
               ) as date_to
from (select t.*,
             lag(EMPLOYEE_TYPE_ID) over (partition by employee_id order by date_from) as prev_et,
             max(date_to) over (partition by employee_id) as max_date_to
      from t
     ) t
where prev_et is null or prev_et <> EMPLOYEE_TYPE_ID;

这种方法的可能优点是它不需要聚合。这可能会带来性能提升。