在三个日期字段上过滤表以创建矩阵

时间:2015-01-06 10:02:48

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

我有一个SQL请求,我似乎无法理解。

我有一张桌子"订阅"包含registrationDate,startDate和endDate。 table

字段registrationDate基本上包含条目创建日期。 (客户订阅的日期) 字段startDate包含订阅将变为"活动"的日期。 字段endDate包含不考虑订阅的日期"活动"了。

在以下示例中,横轴表示两个选定日期(此处为2012-01和2012-04)之间可能的所有注册月份。纵轴表示可以考虑订阅的所有月份"活动"在第一个选定日期(2012-01)和所选日期之后三年之间。 (如果我们拥有所需的所有数据,总共36个月)

example

以下是我的一个请求的结果。

example2

你可以在每一行看到数字" nb"在月份期间创建的订阅" registrationDate",在" startDate"期间开始并在" endDate"。

期间结束

我的问题是,我不知道如何知道在2012-01或其他任何月份变为活动的订阅在一个或一个月之后仍然有效。

注意:我必须在一个sql请求中执行所有操作。矩阵由它生成。

这是我试过的一些方法。结果是不一致/不满意的:

//1----------------------
    SELECT
        CONVERT(varchar(7), sub.startDate, 102) as regMonth
        ,CONVERT(varchar(7), sub.registrationDate, 102) as actMonth
        ,COUNT(sub.id)
    FROM Subscription as sub
    WHERE
            sub.registrationDate >= '2012-01-01' 
        AND sub.registrationDate <= '2013-01-01'
        AND sub.startDate >= sub.registrationDate
        AND sub.endDate <= DATEADD(year, 3, '2012-01-01')
    GROUP BY 
        CONVERT(varchar(7), sub.startDate, 102)
        ,CONVERT(varchar(7), sub.registrationDate, 102)
    ORDER BY 
        regMonth
        ,actMonth

//2----------------------
    SELECT
        CONVERT(varchar(7), sub.registrationDate, 102) as regMonth
        ,CONVERT(varchar(7), act.startDate, 102) as actMonth
        ,COUNT(act.id) as nbActive
    FROM Subscription as sub
    JOIN Subscription as act ON act.clientId = sub.clientId 
                            AND act.startDate >= sub.registrationDate 
                            AND act.startDate <= DATEADD(year, 3, '2012-01-01')
    WHERE
        sub.registrationDate >= '2012-01-01' 
        AND sub.registrationDate <= '2013-01-01'
    GROUP BY
        CONVERT(varchar(7), sub.registrationDate, 102), 
        CONVERT(varchar(7), act.startDate, 102)
    ORDER BY regMonth, actMonth

Here are some data sample。日期从2010年到2014年。

感谢您的帮助!

我也会发布我的进展。

1 个答案:

答案 0 :(得分:0)

以下是示例表

CREATE TABLE #TEMP(STARTDATE DATE,ENDDATE DATE,registrationDate DATE)

INSERT INTO #TEMP 
SELECT '2012-04-23','2012-07-23','2012-04-23'
UNION ALL
SELECT '2012-05-23','2012-07-23','2012-04-23'
UNION ALL
SELECT '2012-06-23','2013-01-23','2012-04-23'
UNION ALL
SELECT '2012-01-23','2012-03-23','2012-05-23'
UNION ALL
SELECT '2012-04-23','2012-07-23','2012-05-23'
UNION ALL
SELECT '2012-06-23','2012-06-23','2012-07-23'
UNION ALL
SELECT '2012-07-23','2012-10-23','2012-07-23'

以下是pivot之前的查询

;WITH CTE AS
(
   -- Filters according to year and get the Id for each StartDate for each registrationDate
   SELECT ROW_NUMBER() OVER(PARTITION BY registrationDate ORDER BY STARTDATE)RNO,*
   FROM #TEMP
   WHERE [endDate]<DATEADD(YEAR,3,[startDate])
)
,CTE2 AS
( 
   -- Get all months between the StartDate and EndDate
   SELECT RNO,registrationDate,STARTDATE ,ENDDATE 
   FROM CTE    

   UNION ALL

   SELECT CTE2.RNO,CTE2.registrationDate,DATEADD(MONTH,1,CTE2.STARTDATE),CTE2.ENDDATE 
   FROM CTE 
   JOIN CTE2 ON CTE2.registrationDate = CTE.registrationDate AND CTE2.RNO = CTE.RNO
   WHERE CTE2.STARTDATE < CTE2.ENDDATE 
)
-- Keeps an extra column to pivot and gets the count of each date for each registrationDate
SELECT DISTINCT registrationDate,STARTDATE [MONTHS],COUNT(STARTDATE) OVER(PARTITION BY registrationDate,STARTDATE) CNT,
CAST(YEAR(registrationDate)AS VARCHAR(4))+'/'+CAST(MONTH(registrationDate)AS VARCHAR(2)) COLS
 INTO #NEWTABLE
 FROM CTE2
ORDER BY registrationDate,STARTDATE
OPTION(MAXRECURSION 0)

获取枢轴列

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + COLS + ']', 
               '[' + COLS + ']')
               FROM    (SELECT DISTINCT registrationDate,COLS FROM #NEWTABLE) PV  
               ORDER BY registrationDate

现在转动它

DECLARE @query NVARCHAR(MAX)
SET @query = '           
              SELECT CAST(YEAR(MONTHS)AS VARCHAR(4))+''/''+CAST(MONTH(MONTHS)AS VARCHAR(2)) [ACTIVE MONTH] 
              ,' + @cols + '
              FROM 
             (
                 SELECT [MONTHS],COLS,CNT FROM #NEWTABLE
             ) x
             PIVOT 
             (
                 MIN(CNT)
                 FOR [COLS] IN (' + @cols + ')
            ) p    
            ORDER BY MONTHS
            '     
EXEC SP_EXECUTESQL @query

希望它有所帮助。