如何根据最大值和最小值将一组 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 记录转换为单行?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据另一列值将一列分成多个?

需要根据表中的唯一值将一列分解为多列?

使用 SQL Query 生成多个最大值和最小值

如何将一系列记录转换为 SQL 中该范围之后的记录值?

sql 根据字段取最小的一条值

JAVA编程-------------24将一组数的最大数放在第一位,最小的数放在最后一位