Sql 筛选三个日期字段上的表以创建矩阵
我有一个SQL请求,我似乎无法理解 我有一个包含registrationDate、startDate和endDate的表订阅。 字段registrationDate基本上包含条目创建日期。客户认购的日期 startDate字段包含订阅激活的日期。 字段endDate包含订阅不再被视为活动的日期 在以下示例中,横轴表示此处选择的2012-01和2012-04两个日期之间可能的所有注册月份。纵轴表示从第一个选择的日期2012-01到选择的日期后三年之间,可以认为订阅处于活动状态的所有月份。如果我们有所有需要的数据,总共36个月 这是我的一个请求的结果 您可以在每行上看到在月注册日期期间创建的订阅编号nb,从startDate开始,到endDate结束 我的问题是,我不知道如何知道在2012-01年或任何其他月份开始活跃的订阅在一个月或X个月后仍然活跃 注意:我必须在一个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到选择的日期后三年之间,可以认为订阅处于活动状态的所有月份。如果我们
//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