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