如何解决需要根据T-SQL中“收录日期”列计算出的第一个“ 3个月”,向列中的每个值添加3个月
我有14K条记录表,如下所示(与一个特定的client_id = 1002相关的数据示例): (我的日期格式为mm / dd / yyyy,月份优先)
ClientsEpisodes:
client_id adm_date disch_date
1002 3/11/2005 5/2/2005
1002 8/30/2005 2/16/2007
1002 3/16/2017 NULL
在sql Server(T-sql)中-我需要在新列[3Month Date]中计算+ 3个月的日期,其中将从我现有的[adm_date]列中计算出第一个“ + 3个月”值。然后,应将[3Months Date]中的值再加上+ 3个月,然后将[3Months Date]列中的下3个值添加至下一个值,依此类推,直到[3MonthsDate]
以下是我期望看到的结果: (我用不同的颜色突出显示了我的日期偏移量,以获得更好的视图)
下面,我将对每个填充(或未填充)的数据集进行更详细的说明:
我在ClientsEpisode表中的第一个[adm_date]是2005年3月11日。 加3个月: 2005年3月11日+ 3个月= 2005年6月11日-属于初始[发布日期](5/2/2005)之后-未填充
Next [adm_date] from ClientEpisode is 8/3/2005 + 3 Months = 11/30/2005;
then + 3 months must be added to 11/30/2005 = 2/30/2006;
then 2/30/2006 + 3 months = 5/30/2006;
then 5/30/2006 + 3 months = 8/30/2006;
then 8/30/2006 + 3 months = 11/30/2006;
then 11/30/2006 + 3 months = 3/2/2007 - falls AFTER my [disch_date]
(2/16/2007) - not populated
下一个[adm_date]-[disch_date]使用相同的算法设置11/5 / 2007-2 / 7/2009(深蓝色)。
然后,其中[adm_date] = 3/16/17,我有[disch_date] IS NULL,因此,该算法适用于 [3个月日期]
解决方法
您可以使用recursive common expression
。下面是一个例子。请注意,您可以将DATEADD
部分与其他部分进行更改(例如,如果需要,可以增加90天)-这是业务逻辑的问题。
DECLARE @DataSource TABLE
(
[client_id] INT,[adm_date] DATE,[disch_date] DATE
);
INSERT INTO @DataSource ([client_id],[adm_date],[disch_date])
VALUES (1002,'3/11/2005 ','5/2/2005'),(1002,'8/30/2005 ','2/16/2007'),'3/16/2017 ',NULL);
WITH DataSource AS
(
SELECT ROW_NUMBER() OVER(ORDER BY [client_id]) AS [row_id],[client_id],DATEADD(MONTH,3,[adm_date]) AS [3Month Date],ISNULL([disch_date],GETUTCDATE()) AS [disch_date]
FROM @DataSource
WHERE DATEADD(MONTH,[adm_date]) <= ISNULL([disch_date],GETUTCDATE())
),RecursiveDataSource AS
(
SELECT [row_id],[3Month Date],[disch_date],0 AS [level]
FROM DataSource
UNION ALL
SELECT DS.[row_id],DS.[client_id],DS.[adm_date],RDS.[3Month Date]),DS.[disch_date],[level] + 1
FROM RecursiveDataSource RDS
INNER JOIN DataSource DS
ON RDS.[row_id] = DS.[row_id]
AND DATEADD(MONTH,RDS.[3Month Date]) < DS.[disch_date]
)
SELECT *
FROM RecursiveDataSource
ORDER BY [row_id],[level];
,
这个问题已经有了一个可以接受的答案,但是您在注释中说您遇到了性能问题。改用此方法-也更简单。
如果下一行的值取决于上一行的值,那么递归CTE非常有用。
在这里,我们不需要上一行的答案-我们只需添加 n x 3个月(例如3个月,6个月,9个月),然后过滤您想要的行保持。
因此,只需执行set逻辑即可执行递归CTE。
以下是一些数据设置:
CREATE TABLE #Datasource (client_id int,adm_date date,disch_date date);
INSERT INTO #Datasource (client_id,adm_date,disch_date) VALUES
(1002,'20050311','20050502'),'20050830','20070216'),'20170316',NULL),'20071105','20090207');
这是简单的SELECT
WITH DataSourceMod AS
(SELECT client_id,disch_date,ISNULL(disch_date,getdate()) AS disc_date_mod
FROM #Datasource
),Nums_One_to_OneHundred AS
(SELECT a * 10 + b AS n
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) A(a)
CROSS JOIN (VALUES (1),(9),(10)) B(b)
)
SELECT ds.client_id,ds.adm_date,ds.disch_date,DATEADD(month,3*Nums.n,ds.adm_date) AS ThreeMonthDate
FROM DataSourceMod ds
CROSS JOIN Nums_One_to_OneHundred Nums
WHERE DATEADD(month,3* Nums.n,ds.adm_date) <= ds.disc_date_mod
ORDER BY ds.client_id,ds.adm_date;
这是
- 计算有效卸货日期(指定的日期或今天)
- 计算未来300个月内所有可能的行(表One_to_OneHundred .. um ..的所有值从1到100,然后乘以3。)
- 只接受那些符合日期条件的人
如果需要,您可以通过限制需要添加的3个月数来进一步优化此设置。这是一个粗略的版本。
WITH DataSourceMod AS
(SELECT client_id,getdate()) AS disc_date_mod,FLOOR(DATEDIFF(month,getdate())) / 3) + 1 AS nMax
FROM #Datasource
),ds.adm_date) AS ThreeMonthDate
FROM DataSourceMod ds
INNER JOIN Nums_One_to_OneHundred Nums ON Nums.n <= ds.nMax
WHERE DATEADD(month,ds.adm_date;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。