SQL:从一组日期范围创建新的日期范围组
SQL: Create new groups of Date Ranges from a Set of Date Ranges
我正在尝试为我的问题找到合适的标题,到目前为止已经尝试了 30 分钟...:)
到目前为止,我有以下示例
DateFrom DateTo Amount
2015/01/01 2015/08/31 1$
2015/01/01 2015/12/31 3$
2015/08/01 2015/12/31 7$
- 第一行我们得到 0.125 美元/月(1 美元/8 个月)
- 对于第二行,我们得到 0.25 美元/月(3 美元/12 个月)
- 对于第 3 行,我们得到 1.4 美元/月(7 美元/5 个月)
考虑到上述情况,我们想创建一组新的日期范围以获得金额总和。类似于下面的结果:
DateFrom DateTo Amount
2015/01/01 2015/07/31 (0.125$+0.25$)*7 =2.625$
2015/08/01 2015/08/31 (1.4$+0.125$+0.25$)*1 =1.775$
2015/09/01 2015/12/31 (1.4$+0.25$)*4 =6.6$
以上加起来和原来的数据一样是11$。我们想要的结果实际上是每组唯一日期范围的金额总和。
这可以用 SQL 实现吗?
解决方案不是很优雅,可能有一些不必要的部分,但它产生了正确的结果:
SELECT * INTO tbl_Periods
FROM ( VALUES
('2015/01/01','2015/08/31',1),
('2015/01/01','2015/12/31',3),
('2015/08/01','2015/12/31',7)) as x(DateFrom,DateTo,Amount);
GO
;WITH
Pass0 as (select 1 as C union all select 1),
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B)
, CTE1 as (
SELECT *, Amount / DateDiff(MONTH, DateFrom, DATEADD(day, 1 ,DateTo)) as MRate
FROM tbl_Periods
)
, CTEM as (SELECT MIN(DateFrom) as MinDate, DATEADD(day, 1, MAX(DateTo) ) as MaxDate
, DateDiff(MONTH, MIN(DateFrom), DATEADD(day, 1, MAX(DateTo) )) as NPeriods FROM tbl_Periods)
, CTEP as (
SELECT TOP ((SELECT NPeriods FROM CTEM)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as RNumber
FROM Pass3 as p
)
, PeriodList as (
SELECT DateAdd(month, RNumber-1,MinDate) as PeriodStarts, DateAdd(month, RNumber,DATEADD(day,-1,MinDate)) as PeriodEnds
FROM CTEM as m CROSS JOIN CTEP as p)
, MPerriods as (
SELECT *
FROM CTE1 as c
INNER JOIN PeriodList as l
ON l.PeriodStarts between c.DateFrom and c.DateTo)
, CPeriods as (
SELECT PeriodStarts, PeriodEnds, SUM(MRate) as MRate
, RNK = RANK() OVER(ORDER BY PeriodStarts)
- RANK() OVER(PARTITION BY SUM(MRate) ORDER BY PeriodStarts)
FROM MPerriods
GROUP BY PeriodStarts, PeriodEnds
)
SELECT MIN(PeriodStarts) as PeriodStarts, MAX(PeriodEnds) as PeriodEnds, COUNT(*) * MRate
FROM CPeriods
GROUP BY MRate, RNK
ORDER BY 1;
GO
我正在尝试为我的问题找到合适的标题,到目前为止已经尝试了 30 分钟...:) 到目前为止,我有以下示例
DateFrom DateTo Amount
2015/01/01 2015/08/31 1$
2015/01/01 2015/12/31 3$
2015/08/01 2015/12/31 7$
- 第一行我们得到 0.125 美元/月(1 美元/8 个月)
- 对于第二行,我们得到 0.25 美元/月(3 美元/12 个月)
- 对于第 3 行,我们得到 1.4 美元/月(7 美元/5 个月)
考虑到上述情况,我们想创建一组新的日期范围以获得金额总和。类似于下面的结果:
DateFrom DateTo Amount
2015/01/01 2015/07/31 (0.125$+0.25$)*7 =2.625$
2015/08/01 2015/08/31 (1.4$+0.125$+0.25$)*1 =1.775$
2015/09/01 2015/12/31 (1.4$+0.25$)*4 =6.6$
以上加起来和原来的数据一样是11$。我们想要的结果实际上是每组唯一日期范围的金额总和。
这可以用 SQL 实现吗?
解决方案不是很优雅,可能有一些不必要的部分,但它产生了正确的结果:
SELECT * INTO tbl_Periods
FROM ( VALUES
('2015/01/01','2015/08/31',1),
('2015/01/01','2015/12/31',3),
('2015/08/01','2015/12/31',7)) as x(DateFrom,DateTo,Amount);
GO
;WITH
Pass0 as (select 1 as C union all select 1),
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B)
, CTE1 as (
SELECT *, Amount / DateDiff(MONTH, DateFrom, DATEADD(day, 1 ,DateTo)) as MRate
FROM tbl_Periods
)
, CTEM as (SELECT MIN(DateFrom) as MinDate, DATEADD(day, 1, MAX(DateTo) ) as MaxDate
, DateDiff(MONTH, MIN(DateFrom), DATEADD(day, 1, MAX(DateTo) )) as NPeriods FROM tbl_Periods)
, CTEP as (
SELECT TOP ((SELECT NPeriods FROM CTEM)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as RNumber
FROM Pass3 as p
)
, PeriodList as (
SELECT DateAdd(month, RNumber-1,MinDate) as PeriodStarts, DateAdd(month, RNumber,DATEADD(day,-1,MinDate)) as PeriodEnds
FROM CTEM as m CROSS JOIN CTEP as p)
, MPerriods as (
SELECT *
FROM CTE1 as c
INNER JOIN PeriodList as l
ON l.PeriodStarts between c.DateFrom and c.DateTo)
, CPeriods as (
SELECT PeriodStarts, PeriodEnds, SUM(MRate) as MRate
, RNK = RANK() OVER(ORDER BY PeriodStarts)
- RANK() OVER(PARTITION BY SUM(MRate) ORDER BY PeriodStarts)
FROM MPerriods
GROUP BY PeriodStarts, PeriodEnds
)
SELECT MIN(PeriodStarts) as PeriodStarts, MAX(PeriodEnds) as PeriodEnds, COUNT(*) * MRate
FROM CPeriods
GROUP BY MRate, RNK
ORDER BY 1;
GO