填充没有定义结束日期的日期列表 - SQL server

时间:2016-02-08 08:32:00

标签: sql-server

我有一个帐户列表及其费用,每隔几天就会更改一次。 在此列表中,每次成本更新为新结果时,我只有开始日期,但结束日期没有列。 这意味着,我需要填写特定帐户和费用的结束日期的日期列表,并将其推断为具有新费用的同一帐户的开始日期。

或多或少那样:
帐户开始日期费用 一个1/1/2016 100 $
两个1/1/2016 150 $
一个4/1/2016 200 $
两个3/1/2016 200 $

我需要的结果是:
帐户日期费用 一个1/1/2016 100 $
一个2/1/2016 100 $
一个3/1/2016 100 $
一个4/1/2016 200 $
两个1/1/2016 150 $
两个2/1/2016 150 $
两个3/1/2016 200 $

例如,如果成本在月中更改,则样本数据将只保留两条记录(每个唯一的帐户开始日期成本组合一条),而结果将保留30条记录每月的每一天的费用(第一笔费用为15英镑,第二笔费用为15英镑)。成本是给定的,无需计算(手动插入)。

请注意,结果包含更多记录,因为样本数据仅显示该帐户的开始日期和更新费用。虽然结果显示了每月的每一天的成本。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

解决方案有点长。

我为测试目的添加了额外的日期:

DECLARE @t table(account varchar(10), startdate date, cost int)

INSERT @t 
values
('one','1/1/2016',100),('two','1/1/2016',150),
('one','1/4/2016',200),('two','1/3/2016',200),
('two','1/6/2016',500) -- extra row

;WITH CTE as
( SELECT
    row_number() over (partition by account order by startdate) rn,
    *
  FROM @t
),N(N)AS 
(
  SELECT 1 FROM(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))M(N)
),
tally(N) AS -- tally is limited to 1000 days
(
  SELECT ROW_NUMBER()OVER(ORDER BY N.N) - 1 FROM N,N a,N b
),GROUPED as
(
  SELECT
    cte.account, cte.startdate, cte.cost, cte2.cost cost2, cte2.startdate enddate
  FROM CTE
  JOIN CTE CTE2
  ON CTE.account = CTE2.account
  and CTE.rn = CTE2.rn - 1
)
-- used DISTINCT to avoid overlapping dates
SELECT DISTINCT
  CASE WHEN datediff(d, startdate,enddate) = N THEN cost2 ELSE cost END cost,
  dateadd(d, N, startdate) startdate,
  account
FROM grouped
JOIN tally
ON datediff(d, startdate,enddate) >= N

结果:

cost  startdate   account
100   2016-01-01  one
100   2016-01-02  one
100   2016-01-03  one
150   2016-01-01  two
150   2016-01-02  two
200   2016-01-03  two
200   2016-01-04  one
200   2016-01-04  two
200   2016-01-05  two
500   2016-01-06  two

答案 1 :(得分:0)

谢谢@ t-clausen.dk!

它没有完全解决问题,但确实以正确的方式指导我。

最后,我使用LEAD函数为每个帐户的每个费用生成结束日期,然后我可以根据that idea填充日期列表。

以下是我如何生成结束日期:

DECLARE @t table(account varchar(10), startdate date, cost int)
INSERT @t 
values
('one','1/1/2016',100),('two','1/1/2016',150),
('one','1/4/2016',200),('two','1/3/2016',200),
('two','1/6/2016',500)

select account 
      ,[startdate]
      ,DATEADD(DAY, -1, LEAD([Startdate], 1,'2100-01-01') OVER (PARTITION BY account ORDER BY [Startdate] ASC)) AS enddate 
      ,cost
from @t

它返回了预期的结果:

帐户启动日期结束日期 一2016-01-01 2016-01-03 100
一2016-01-04 2099-12-31 200
二2016-01-01 2016-01-02 150
二2016-01-03 2016-01-05 200
二2016-01-06 2099-12-31 500

请注意,我将当前费用的结束日期设置为远期的某个日期,这意味着(对我来说)他们当前处于活动状态。