在SQL中将日期范围分隔为单独的段

时间:2010-03-22 17:36:26

标签: sql date

我有一个包含2个日期字段和一个标识符(id,fromdate和todate)的表格。这些日期以任何可能的方式重叠。我需要生成一个段列表,每个段都有一个描述该列表中不同段的开始和结束日期。

例如:

id,  FromDate    ToDate
1,   1944-12-11, 1944-12-31
2,   1945-01-01, 1945-12-31
3,   1945-01-01, 1945-06-30
4,   1945-12-31, 1946-05-01
5,   1944-12-17, 1946-03-30

应该产生所有重叠的所有部分:

1,   1944-12-11, 1944-12-16
1,   1944-12-17, 1944-12-31
5,   1944-12-17, 1944-12-31
2,   1945-01-01, 1945-06-30
3,   1945-01-01, 1945-06-30
5,   1945-01-01, 1945-06-30
2,   1945-07-01, 1945-12-09
5,   1945-07-01, 1945-12-09
2,   1945-12-10, 1945-12-31
4,   1945-12-10, 1945-12-31
5,   1945-12-10, 1945-12-31
4,   1946-01-01, 1946-03-30
5,   1946-01-01, 1946-03-30
4,   1946-04-01, 1946-05-01

或者图表可能有帮助

INPUT
1 <---->
2       <----------->
3       <----->
4                 <---------->
5    <----------------->

OUTPUT
1 <->
1    <->
5    <->
2       <----->
3       <----->
5       <----->
2              <->
5              <->
2                 <->
4                 <->
5                 <->
4                    <->
5                    <->
4                       <---->

请帮忙

2 个答案:

答案 0 :(得分:2)

You can use this SO question's answer as a basis

它分成了这个输出,但我认为很容易变成你需要的东西:

OUTPUT
1                 <->
1,5                  <->
2,3,5                   <----->
...

This link should also prove helpful - 它仅显示如何构建范围。

答案 1 :(得分:0)

尝试以下脚本

SCHEMA

CREATE TABLE splitDates
    ([member] int, effdt datetime, termdt datetime)
;

INSERT INTO splitDates
    ([member], effdt, termdt)
VALUES
(1,   '1944-12-11', '1944-12-31'),
(2,   '1945-01-01', '1945-12-31'),
(3,   '1945-01-01', '1945-06-30'),
(4,   '1945-12-31', '1946-05-01'),
(5,   '1944-12-17', '1946-03-30');

SQL脚本

DECLARE @SplitRanges TABLE ([member] int, theDate datetime, des varchar(10));

INSERT INTO @SplitRanges
SELECT  DISTINCT
 m.member, 
 memDt.theDate,
 memdt.des
FROM splitDates m
JOIN ( SELECT DISTINCT  effdt as theDate,'effdt' des FROM splitDates
    union all
    SELECT DISTINCT  effdt-1 as theDate,'trmdt' des FROM splitDates
    union all
    SELECT DISTINCT  termdt as theDate,'trmdt' des FROM splitDates
    union all
    SELECT DISTINCT  termdt+1 as theDate,'effdt' des FROM splitDates
    ) as memDt on 1=1
WHERE memDt.theDate >= m.effdt 
  AND memDt.theDate <= m.termdt
ORDER BY m.member, memdt.thedate;

;WITH rowNumbers as (
SELECT ef.member, ef.thedate,ef.des, 
ROW_NUMBER() over (PARTITION BY  ef.member ORDER BY ef.thedate ASC) AS rn
FROM @SplitRanges ef
)
SELECT DISTINCT ef.member, ef.thedate as effdt, tm.thedate as termdt FROM rowNumbers ef
JOIN rownumbers tm on tm.member=ef.member and ef.rn+1=tm.rn
WHERE ef.des='effdt'
order by ef.thedate

输出

member  effdt               termdt
1   1944-12-11 00:00:00.000 1944-12-16 00:00:00.000
1   1944-12-17 00:00:00.000 1944-12-31 00:00:00.000
5   1944-12-17 00:00:00.000 1944-12-31 00:00:00.000
2   1945-01-01 00:00:00.000 1945-06-30 00:00:00.000
3   1945-01-01 00:00:00.000 1945-06-30 00:00:00.000
5   1945-01-01 00:00:00.000 1945-06-30 00:00:00.000
2   1945-07-01 00:00:00.000 1945-12-30 00:00:00.000
5   1945-07-01 00:00:00.000 1945-12-30 00:00:00.000
2   1945-12-31 00:00:00.000 1945-12-31 00:00:00.000
4   1945-12-31 00:00:00.000 1945-12-31 00:00:00.000
5   1945-12-31 00:00:00.000 1945-12-31 00:00:00.000
4   1946-01-01 00:00:00.000 1946-03-30 00:00:00.000
5   1946-01-01 00:00:00.000 1946-03-30 00:00:00.000
4   1946-03-31 00:00:00.000 1946-05-01 00:00:00.000