基于重叠日期拆分行并更新开始和结束日期

时间:2016-07-27 09:08:44

标签: sql sql-server sql-server-2008 tsql

编辑涵盖所有案例

我对SQL(SQL Server 2008)相对较新,我的问题陈述如下。表中的数据可以包含重叠的持续时间,但这需要分离出来(在样本数据集下面)

表中的数据如下:

Column 1    |Column 2   |StartTime  |EndTime    |Factor

  A           |B          |Jan 1      |Jun  30     |0.7
  A           |B          |Feb 1      |September 30|0.3
  A           |B          |Mar  1     |August   31 |0.2

所需的输出如下:

 Column 1   |Column 2   |StartTime  |EndTime    |Factor
   A         |B           |Jan  1    |Jan 31    |0.7
   A         |B           |Feb 1     |Feb 28    |1.0
   A         |B           |Mar 1     |Jun 30    |1.2
   A         |B           |Jul 1     |August 31 |0.5
   A         |B           |Sept 1    |Sept 30   |0.3

要求是每当第1列和第2列相同并且日期重叠时,应该将因子加总,并且应该创建具有新的开始和结束时间的新记录,以便存在连续性。 / p>

开始和结束时间采用DATETIME格式。

我尝试使用自联接,但没有到达任何地方。有没有人有任何建议?

1 个答案:

答案 0 :(得分:0)

    DECLARE @MD AS int;

SELECT @MD = MAX(YEAR(a2.STARTTIME) * 100 + MONTH(a2.ENDTIME)) FROM ashtable a2;

WITH MTHS AS    (
                    SELECT MIN(YEAR(STARTTIME) * 100 + MONTH(STARTTIME)) TheMonth FROM ashtable
                    UNION ALL 
                    SELECT TheMonth + 1  FROM MTHS WHERE TheMonth < @MD
                ),
     ALLMONTHS AS 
                (
                    select a.Column1,a.column2,m.TheMonth, SUM(FACTOR) f from mths m 
                                LEFT JOIN 
                                    ashtable a 
                                        ON m.TheMonth >= YEAR(a.STARTTIME) * 100 + MONTH(a.STARTTIME) 
                                        AND 
                                        m.TheMonth <= YEAR(a.ENDTIME) * 100 + MONTH(a.ENDTIME)
                        GROUP BY a.Column1,a.column2, m.TheMonth
                ),
     RNS AS
                (SELECT  a.Column1,a.column2,a.TheMonth, a.f, a.f - COALESCE(b.f, -99999999.99) dif FROM ALLMONTHS a 
                                        LEFT JOIN ALLMONTHS b ON a.TheMonth = b.TheMonth + 1 AND a.column1=b.column1 and a.column2=b.column2),   
    ISLANDS AS (
                select  a.Column1,a.column2,a.TheMonth, 
                        MIN(b.TheMonth) MonthEnd, 
                        MIN(A.f) Factor 
                                from RNS a 
                                    LEFT JOIN RNS b ON a.column1=b.column1 and a.column2=b.column2 and b.TheMonth > a.TheMonth AND b.f <> a.f WHERE a.dif <> 0
                                GROUP BY a.column1,a.column2,a.TheMonth
                )               
    SELECT  Column1,column2,dateadd(month, (themonth - 1) % 100, 
            DateADD(year,(Themonth) / 100 - 1900, 0)) s, 
            dateadd(day,-1,dateadd(month, (themonth) % 100, 
            DateADD(year,(Themonth) / 100 - 1900, 0))) e, factor  FROM ISLANDS order by column1,column2,s

我的输出(包括不同列键的测试行)

    Column1    column2    s                       e                       factor
---------- ---------- ----------------------- ----------------------- -------
A          B          2016-01-01 00:00:00.000 2016-01-31 00:00:00.000 0.7
A          B          2016-02-01 00:00:00.000 2016-02-29 00:00:00.000 1.0
A          B          2016-03-01 00:00:00.000 2016-03-31 00:00:00.000 1.2
A          B          2016-07-01 00:00:00.000 2016-07-31 00:00:00.000 0.5
A          B          2016-09-01 00:00:00.000 2016-09-30 00:00:00.000 0.3
A          C          2016-01-01 00:00:00.000 2016-01-31 00:00:00.000 99.0

这是一个修改过的版本,抛弃了我将失败的想法表示为整数

    DECLARE @MD AS datetime;

SELECT @MD = MAX(endtime) FROM ashtable a2;

WITH MTHS AS    (
                    SELECT MIN(STARTTIME) TheMonth FROM ashtable
                    UNION ALL 
                    SELECT dateadd(month,1,TheMonth) TheMonth  FROM MTHS WHERE TheMonth < @MD
                ),

     ALLMONTHS AS 
                (
                    select a.Column1,a.column2,m.TheMonth, SUM(FACTOR) f from mths m 
                                LEFT JOIN 
                                    ashtable a 
                                        ON m.TheMonth >= a.starttime
                                        AND 
                                        m.TheMonth < a.endtime 
                        GROUP BY a.Column1,a.column2, m.TheMonth
                ),
     RNS AS
                (SELECT  a.Column1,a.column2,a.TheMonth, a.f, a.f - COALESCE(b.f, -99999999.99) dif FROM ALLMONTHS a 
                                        LEFT JOIN ALLMONTHS b ON a.TheMonth = dateadd(month,1,b.TheMonth) AND a.column1=b.column1 and a.column2=b.column2),  
    ISLANDS AS (
                select  a.Column1,a.column2,a.TheMonth,dq2.lastmonth,a.f factor
                    from RNS a
                    CROSS APPLY
                        (SELECT TOP 1 * FROM (SELECT 1 as ord, b.TheMonth lastmonth FROM RNS b WHERE a.Column1 = b.column1 and a.column2=b.column2 and b.themonth>a.themonth and a.f <> b.f 
                        union SELECT 2 as ord, dateadd(month,1,max(c.themonth)) lastmonth  from rns c where a.Column1 = c.column1 and a.column2=c.column2) dq ORDER BY DQ.ord) dq2
                        where a.dif<>0
                        --MIN(b.TheMonth) MonthEnd, 
                        --MIN(A.f) Factor 
                        --      from RNS a 
                        --          LEFT JOIN RNS b ON a.column1=b.column1 and a.column2=b.column2 and b.TheMonth > a.TheMonth AND b.f <> a.f where a.dif<>0
                        --      GROUP BY a.column1,a.column2,a.TheMonth
                )   


    SELECT  Column1,column2,themonth, dateadd(day,-1,lastmonth),
             factor  FROM ISLANDS order by column1,column2,themonth