根据更改(T-SQL)将数据拆分为时间间隔

时间:2017-11-08 09:22:42

标签: sql-server tsql date-range

假设我有两张桌子:

薪酬

PersonId, StartDate, EndDate, Salary

标题

PersonId, StartDate, EndDate, Title

一个人的工资与他的头衔无关,可以随时改变。

如何最好地获得薪资和职称不变的所有连续StartDate / EndDate时间间隔?

所以这......

薪酬

Me | 2017-01-01 | 2017-01-31 | 2000
Me | 2017-02-01 | 2017-05-31 | 2100
Me | 2017-06-01 | 2017-07-31 | 2300

标题

Me | 2017-01-01 | 2017-03-31 | Junior
Me | 2017-04-01 | 2017-07-31 | Senior

将返回:

SalaryAndTitle

Me | 2017-01-01 | 2017-01-31 | 2000 | Junior
Me | 2017-02-01 | 2017-03-31 | 2100 | Junior
Me | 2017-04-01 | 2017-05-31 | 2100 | Senior
Me | 2017-06-01 | 2017-07-31 | 2300 | Senior

这是一个简化的例子。在我的实际情况中,会有许多更改列,并且结果数据集仍应包含时间间隔,其中这些列相对于该时间段具有未更改的值。

我正在考虑over( partition by...),但我无法让它发挥作用。任何帮助表示赞赏。

干杯,

2 个答案:

答案 0 :(得分:0)

我不知道你的性能要求,我相信会有更好的方法,但是......

一种解决这些问题的方法是每天将其分解,然后使用标准聚合函数,例如下面我假设您有一个名为日期的表,其中包含您感兴趣的所有日期: / p>

select 
    p.personid
    ,min(ds.dt) as from 
    ,max(ds.dt) as to
    ,s.salary
    ,t.title
from
    dates as ds
    cross join 
        (select distinct personid from salary) as p
    left outer join salary as s
        on ds.dt >= s.startdate
        and ds.dt <= s.enddate
        and p.personid = s.personid
    left outer join title as t
        on ds.dt >= t.startdate
        and ds.dt <= t.enddate
        and p.personid = t.personid
group by
    p.personid
    ,s.salary
    ,t.title

我在这里使用左外连接,因为我将从那开始并对数据进行一些分析。

我使用这种类型的东西进行分析,报告和数据迁移。我也用它进行计费计算 - 但是我完全没有对这种方法进行性能测试。重点是编写易于维护的查询,并拥有您可能想要的所有功能(分析往往更容易使用高度非标准化的数据,如日常故障)

答案 1 :(得分:0)

我在示例数据中添加了一些记录,以解决围绕PersonID具有多个时间范围的可能性的问题,其中PersonID具有相同的Title和{{ 1}}。

<强>答案:

Salary

子查询会复制create table dbo.Salary ( PersonID varchar(3) , StartDate date , EndDate date , Salary int ) create table dbo.Title ( PersonID varchar(3) , StartDate date , EndDate date , Title varchar(10) ) insert into dbo.Salary values ('Me', '2017-01-01', '2017-01-31', 2000) , ('Me', '2017-02-01', '2017-05-31', 2100) , ('Me', '2017-06-01', '2017-07-31', 2300) , ('You', '2017-01-01', '2017-03-31', 2400) , ('You', '2017-04-01', '2017-08-31', 2500) , ('You', '2017-09-01', '2017-12-31', 2400) insert into dbo.Title values ('Me', '2017-01-01', '2017-03-31', 'Junior') , ('Me', '2017-04-01', '2017-07-31', 'Senior') , ('You', '2017-01-01', '2017-02-28', 'Junior') , ('You', '2017-03-01', '2017-05-31', 'Senior') , ('You', '2017-06-01', '2017-12-31', 'Junior') select a.PersonID , a.StartDate , a.EndDate , a.Salary , a.Title from ( select s.PersonID , iif(s.StartDate < t.StartDate, t.StartDate, s.StartDate) as StartDate , iif(s.EndDate < t.EndDate, s.EndDate, t.EndDate) as EndDate , s.Salary , t.Title from dbo.Salary as s inner join dbo.Title as t on s.PersonID = t.PersonID ) as a where 1=1 and datediff(d, a.StartDate, a.EndDate) >= 0 --is it a valid time range? 的所有可能的StartDate / EndDate组合,外部查询会确定该时间范围是否有效。

<强>输出:

PersonID