按行检测列更改
Detect column change by row
首先,我确实搜索过类似的代码,但没有找到合适的。
我想要做的是显示每个员工的 employee_type_id 变化时的行,列出 employee_id,date 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_id
和 employee_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;
这种方法的可能优点是它不需要聚合。这可能会带来性能提升。
首先,我确实搜索过类似的代码,但没有找到合适的。
我想要做的是显示每个员工的 employee_type_id 变化时的行,列出 employee_id,date 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_id
和 employee_type_id
.
这是使用 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;
这种方法的可能优点是它不需要聚合。这可能会带来性能提升。