微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

需要根据T-SQL中“收录日期”列计算出的第一个“ 3个月”,向列中的每个值添加3个月

如何解决需要根据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]

以下是我期望看到的结果: (我用不同的颜色突出显示了我的日期偏移量,以获得更好的视图)

enter image description here

下面,我将对每个填充(或未填充)的数据集进行更详细的说明:

我在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 举报,一经查实,本站将立刻删除。