Sql 筛选三个日期字段上的表以创建矩阵

Sql 筛选三个日期字段上的表以创建矩阵,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一个SQL请求,我似乎无法理解 我有一个包含registrationDate、startDate和endDate的表订阅。 字段registrationDate基本上包含条目创建日期。客户认购的日期 startDate字段包含订阅激活的日期。 字段endDate包含订阅不再被视为活动的日期 在以下示例中,横轴表示此处选择的2012-01和2012-04两个日期之间可能的所有注册月份。纵轴表示从第一个选择的日期2012-01到选择的日期后三年之间,可以认为订阅处于活动状态的所有月份。如果我们

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

我有一个包含registrationDate、startDate和endDate的表订阅。

字段registrationDate基本上包含条目创建日期。客户认购的日期 startDate字段包含订阅激活的日期。 字段endDate包含订阅不再被视为活动的日期

在以下示例中,横轴表示此处选择的2012-01和2012-04两个日期之间可能的所有注册月份。纵轴表示从第一个选择的日期2012-01到选择的日期后三年之间,可以认为订阅处于活动状态的所有月份。如果我们有所有需要的数据,总共36个月

这是我的一个请求的结果

您可以在每行上看到在月注册日期期间创建的订阅编号nb,从startDate开始,到endDate结束

我的问题是,我不知道如何知道在2012-01年或任何其他月份开始活跃的订阅在一个月或X个月后仍然活跃

注意:我必须在一个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
。日期从2010年到2014年

谢谢你的帮助


我也会发布我的预付款。

这是示例表

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 @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

希望有帮助。

你能提供更多的数据示例吗?因为你的意思不清楚。我在示例中添加了解释。如果您需要更多,请告诉我。如果您可以添加基础数据以支持您的编辑,这将有所帮助。另外,如果订阅的结束日期为未来3年,那么当您说订阅处于活动状态时,您的意思是,在您的示例数据中,没有订阅处于活动状态,因为没有订阅的结束日期为未来3年?您可以找到我导出的一些数据。我忘了精确的结束日期是什么是sub.id@Poutchyukit看起来就是这样!但是我现在没有时间去测试它。我会尽快做的。令人印象深刻的查询顺便说一句!请随时请求@poutchyuksadly进行任何更改,此请求存在性能问题。我的表由数千个条目组成,我从未在CTE2中传递过递归。我调整了过滤器以改善它,但没有效果@Sarath AvanavBusiness您需要StartDate和EndDate之间的所有月份,而且您的表非常大,性能是一个问题。另一种选择是使用游标,尽管存在性能问题,但它比递归CTE更好@普切克
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