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

Sql server 根据更改将数据拆分为时间间隔(T-SQL),sql-server,tsql,date-range,Sql Server,Tsql,Date Range,假设我有两张桌子: 薪金: 标题: 一个人的工资与他的头衔无关,任何一个头衔都可能随时改变 如何才能最好地获得工资和职称不变的所有连续开始日期/结束日期时间间隔 所以这个 薪水 头衔 将返回: 薪水和头衔 这是一个简化的例子。在我的实际案例中,会有许多变化的列,结果数据集应该仍然包含时间间隔,其中这些列相对于该时间段具有不变的值 我在考虑用。。。但我不能让它工作。谢谢你的帮助 干杯 Kim我不知道您对性能的要求,我相信会有更好的方法来做到这一点,但是 解决这些问题的一种综合解决方案是逐日分解,然

假设我有两张桌子:

薪金:

标题:

一个人的工资与他的头衔无关,任何一个头衔都可能随时改变

如何才能最好地获得工资和职称不变的所有连续开始日期/结束日期时间间隔

所以这个

薪水

头衔

将返回:

薪水和头衔

这是一个简化的例子。在我的实际案例中,会有许多变化的列,结果数据集应该仍然包含时间间隔,其中这些列相对于该时间段具有不变的值

我在考虑用。。。但我不能让它工作。谢谢你的帮助

干杯


Kim

我不知道您对性能的要求,我相信会有更好的方法来做到这一点,但是

解决这些问题的一种综合解决方案是逐日分解,然后使用标准聚合函数,例如,我假设您有一个名为dates的表,其中包含您感兴趣的所有日期:

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
我在这里使用左外连接,因为我将从它开始,并对数据进行一些分析


我经常使用这种类型的东西进行分析、报告和数据迁移。我也使用它进行计费计算——但是我绝对没有对这种方法进行性能测试。重点一直是编写易于维护的查询,并且具有您想要的所有功能。对于高度非标准化的数据,例如逐日细分,分析往往更容易进行。我不知道您的性能要求,我相信会有更好的方法来实现这一点,但是

解决这些问题的一种综合解决方案是逐日分解,然后使用标准聚合函数,例如,我假设您有一个名为dates的表,其中包含您感兴趣的所有日期:

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
我在这里使用左外连接,因为我将从它开始,并对数据进行一些分析


我经常使用这种类型的东西进行分析、报告和数据迁移。我也使用它进行计费计算——但是我绝对没有对这种方法进行性能测试。重点是编写易于维护的查询,并具有您可能想要的所有功能。对于高度非标准化的数据(如逐日细分),分析往往更容易进行。我在样本数据中添加了一些记录,以解决围绕以下问题提出的问题:PersonID可能具有一个以上的时间范围PersonID拥有相同的头衔和薪水

答复:


我在示例数据中添加了一些记录,以解决围绕一个PersonID具有多个时间范围的可能性而提出的问题,其中PersonID具有相同的头衔和薪水

答复:


你好我正在尽可能提高效率。我还认为,在没有实际尝试的情况下,您的解决方案存在一个问题:如果我稍后返回到之前使用不同组合的相同工资和头衔组合,最小值/最大值将设置该组合的跨度,从组合发生的第一天到同一组合发生的最后一天,这不是我想要的。每个人都希望最大效率:D。。我想,您可以将title和salary表中的任何其他列添加到select和group by,以确保不会发生这种情况。前几天我在gordon linoff那里看到的这个可能相关的答案可能会有所帮助,但我还没有抽出时间来弄清楚它的确切工作原理:还有。。我不知道这是否有效,我肯定以这种方式分析了数百万条记录,没有问题,可能值得尝试一下您的真实数据,例如,如果您一次只看一名员工,这可能不会太糟糕?我想可能会涉及很长的时间,它可能仍然很慢!我正在尽可能提高效率。我还认为,在没有实际尝试的情况下,您的解决方案存在一个问题:如果我稍后返回到之前使用不同组合的相同工资和头衔组合,最小值/最大值将设置该组合的跨度,从组合发生的第一天到同一组合发生的最后一天,这不是我想要的。每个人都希望最大效率:D。。我想,您可以将title和salary表中的任何其他列添加到select和group by,以确保不会发生这种情况。前几天我在gordon linoff那里看到的这个可能相关的答案可能会有所帮助,但我还没有抽出时间来弄清楚它的确切工作原理:还有。。我不知道这是否有效,我肯定以这种方式分析了数百万条记录,没有问题,可能值得尝试一下您的真实数据,例如,如果您只查看一个emp loyee在某个时候可能不会太糟糕吧?我想,由于可能涉及很长的时间框架,它可能仍然很慢
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
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
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
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?
PersonID    StartDate    EndDate     Salary  Title
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
You         2017-01-01   2017-02-28  2400    Junior
You         2017-03-01   2017-03-31  2400    Senior
You         2017-04-01   2017-05-31  2500    Senior
You         2017-06-01   2017-08-31  2500    Junior
You         2017-09-01   2017-12-31  2400    Junior