如何根据最大值和最小值将一组 SQL 记录转换为单行?
Posted
技术标签:
【中文标题】如何根据最大值和最小值将一组 SQL 记录转换为单行?【英文标题】:How to convert group of SQL records to the single row basing on max and min values? 【发布时间】:2021-10-30 23:07:32 【问题描述】:我们将员工状态历史记录存储在 SQL Server 表中。有员工 ID(外键)、开始和结束日期以及员工状态列。结束日期列中的 NULL 表示该状态现在处于活动状态。员工可以是活跃的,可以被终止,然后再次活跃。
由于客户端应用程序中的错误,每次更新员工资料时,都会在表中生成新记录,其中开始日期是上一条记录的结束日期(见记录#1,2,3 )。例如,员工 #1 在 1 月 1 日至 4 月 1 日期间处于活动状态,然后他们被解雇了三个月并再次被重新雇用。
Record ID | Employee ID | Start Date | End Date | Employee Status |
---|---|---|---|---|
1 | 1 | 2019-01-01 | 2019-02-01 | Active |
2 | 1 | 2019-02-01 | 2019-03-01 | Active |
3 | 1 | 2019-03-01 | 2019-04-01 | Active |
4 | 1 | 2019-04-01 | 2019-07-01 | Terminated |
5 | 1 | 2019-07-01 | NULL | Active |
6 | 2 | 2019-01-01 | 2019-02-01 | Active |
7 | 2 | 2019-01-01 | NULL | Active |
8 | 3 | 2019-01-01 | NULL | Active |
我们现在无法修复 UI,因此我们计划经常运行该脚本。 我能够以命令式风格编写带有光标/循环的脚本,但我认为性能不会很好,因为我们有大量的员工状态记录(第一次运行)和很多员工.
我想要一个声明性脚本,它将第 1、2、3 行替换为单行,例如:
Record ID | Employee ID | Start Date | End Date | Employee Status |
---|---|---|---|---|
1 | 1 | 2019-01-01 | 2019-04-01 | Active |
感谢您的建议。
【问题讨论】:
【参考方案1】:这是一个间隙和孤岛问题的示例。我建议使用lag()
和累积总和来识别组:
select min(recordid) as recordid, employeeid, status, min(startdate), max(enddate)
from (select t.*,
sum(case when prev_enddate = startdate then 0 else 1 end) over (partition by employeeid order by startdate) as grp
from (select t.*,
lag(enddate) over (partition by employeeid, status order by startdate) as prev_enddate
from t
) t
) t
group by employeeid, status, grp;
基本上,这会查看同一员工和状态的前一行。如果不与当前行相邻,则当前行开始一个新组。
【讨论】:
以上是关于如何根据最大值和最小值将一组 SQL 记录转换为单行?的主要内容,如果未能解决你的问题,请参考以下文章