假设我有一个简单的查询
select
from_date, to_date
from datatable
order by from_date
这将导致
from_date to_date
2018-01-01 2018-04-30
2018-05-01 2018-12-31
我想将日期范围分成几个季度。到目前为止,我得到的结果是:
WITH temp AS
(
SELECT
cast(sd.from_date as date) from_date,
cast(dateadd(day,-1,dateadd(quarter, 1, cast(sd.from_date as date))) as date) AS end_date,
cast(sd.to_date as date) as actual_enddate
FROM (select cast(from_date as date) from_date, to_date from datatable) sd
UNION ALL
SELECT
dateadd(day,1,cast(t.end_date as date)) end_date,
CASE
WHEN dateadd(quarter, 1,t.end_date) < t.actual_enddate THEN dateadd(quarter, 1,t.end_date)
ELSE t.actual_enddate
END AS end_date,
cast(t.actual_enddate as date) actual_enddate
FROM temp t
WHERE t.end_date != t.actual_enddate
)
SELECT
t.from_date,
t.end_date
FROM temp t
ORDER BY t.from_date
OPTION (MAXRECURSION 0)
我的当前输出是:
from_date end_date
2018-01-01 2018-03-31
2018-04-01 2018-04-30
2018-05-01 2018-07-31
2018-08-01 2018-10-31
2018-11-01 2018-12-31
我想将这些记录分成完整的四分之三,以得到如下内容:
from_date end_date
2018-01-01 2018-03-31
2018-04-01 2018-04-30
2018-05-01 2018-06-31
2018-07-01 2018-09-31
2018-10-01 2018-12-31
答案 0 :(得分:1)
这与您要寻找的东西相似吗?
DECLARE @datatable TABLE
(
from_date DATE,
to_date DATE,
value FLOAT
)
INSERT INTO @datatable
(from_date, to_date, value)
VALUES
('2018-01-01','2018-04-30','100'),
('2018-05-01','2018-12-31','100')
;WITH temp AS
(
SELECT
sd.from_date,
DATEADD(DAY,-1, DATEADD(MONTH, 3 - ((MONTH(sd.from_date) -1) % 3), sd.from_date)) AS end_date,
sd.to_date As actual_enddate,
sd.value
FROM @datatable sd
UNION ALL
SELECT
DATEADD(DAY,1, t.end_date) end_date,
CASE
WHEN DATEADD(QUARTER, 1,t.end_date) < t.actual_enddate THEN EOMONTH(DATEADD(QUARTER, 1, t.end_date) )
ELSE t.actual_enddate
END AS end_date,
t.actual_enddate As actual_enddate,
value
FROM temp t
WHERE t.end_date != t.actual_enddate
)
SELECT
t.from_date,
t.end_date,
ROUND((100.0/3.0) * (DATEDIFF(MONTH, t.from_date, DATEADD(DAY, 1, t.end_date))), 2) As Value
FROM temp t
ORDER BY t.from_date
OPTION (MAXRECURSION 0)
答案 1 :(得分:1)
此问题的日期算法相当混乱。您似乎在数月,当您使用季度结束日期时,我发现这很困难。
因此,以下内容添加了一个日期,以将值带入下个月。这仅用于计算,但简化了分区逻辑。
WITH cte AS (
SELECT id, sd.from_date as within_quarter_start_date,
(CASE WHEN quarter_end < to_date THEN quarter_end ELSE to_date END) as within_quarter_end_date,
DATEADD(quarter, DATEDIFF(QUARTER, 0, from_date), 0) as quarter_start,
v.quarter_end,
DATEADD(day, 1, sd.to_date) as to_date,
sd.value, 1 as lev
FROM datatable sd CROSS APPLY
(VALUES (DATEADD(QUARTER, DATEDIFF(QUARTER, 0, from_date) + 1, 0))) v(quarter_end)
UNION ALL
SELECT id, CONVERT(DATE, DATEADD(quarter, 1, quarter_start)),
(CASE WHEN DATEADD(quarter, 1, quarter_end) < to_date THEN DATEADD(quarter, 1, quarter_end) ELSE to_date END) as within_quarter_end_date,
DATEADD(quarter, 1, quarter_start),
DATEADD(quarter, 1, quarter_end),
to_date,
value, lev + 1
FROM cte
WHERE quarter_end < to_date and lev < 10
)
select within_quarter_start_date as from_date,
dateadd(day, -1, within_quarter_end_date) as to_date,
value * (datediff(month, within_quarter_start_date, within_quarter_end_date) ) / 3.0,
quarter_start, quarter_end
from cte
order by 1, 2;
Here是db <>小提琴。