【问题标题】:Dynamic Dates SQL Server动态日期 SQL Server
【发布时间】:2020-09-21 09:56:12
【问题描述】:

我在 SQL 中有以下数据。

我需要找出一种基于以下 2 个值动态获取下一个日期的方法。剩余剂量告诉我需要找到多少个日期,RXDAYS 告诉我查找日期的增量

Date Shipped    Remaining Doses RXDAYS
2019-06-05      2               30

因此,根据上述情况,我会找到 2019-06-05 后 30 天的日期,然后得到 2019-07-05,再过 30 天,我会得到 2019-08-04。

有没有办法做到这一点?

【问题讨论】:

    标签: sql sql-server tsql date recursive-query


    【解决方案1】:

    使用dateadd()。这为您提供了最终日期:

    dateadd(day, doses * rxdays, date_shipped)
    

    另一方面,如果您想生成新行,则可以使用递归查询:

    with cte as (
        select date_shipped mydate, doses, rxdays from mytable
        union all
        select (dateadd(day, rxdays, date_shipped), doses - 1, rxdays 
        from cte
        where doses > 0
    )
    select mydate from cte
    

    对于您问题中显示的示例数据行,这将生成三行,日期为2019-06-052019-07-052019-08-04

    如果doses 的值大于100,则需要在查询的最后添加option(maxrecursion 0)

    【讨论】:

    • 这会让我得到最远的日期,但我需要每个 RXDAYS 增量的日期
    • @James:我在猜测。请参阅我的更新答案。
    • 谢谢我相信这就是我需要的
    【解决方案2】:

    你可以使用DATEADD()函数作为

    SELECT *, CONVERT(DATE, DATEADD(Day, RXDAYS, DateShipped)) FirstDateToFind,
              CONVERT(DATE, DATEADD(Day, RXDAYS * 2, DateShipped)) SecondDateToFind
    FROM
    (
      VALUES
      ('2019-06-05',      2,               30)
    ) T(DateShipped, RemainingDoses, RXDAYS);
    

    更新:

    您似乎正在寻找如下生成行:

    WITH Data AS
    (
      SELECT *
      FROM T
      UNION ALL
      SELECT CONVERT(DATE, DATEADD(Day, (RXDAYS * (RemainingDoses - RemainingDoses + 1)), DateShipped)),
             RemainingDoses - 1,
             RXDAYS
      FROM Data
      WHERE RemainingDoses > 0
    )
    SELECT *
    FROM Data
    ORDER BY DateShipped;
    

    这是db<>fiddle

    【讨论】:

      【解决方案3】:

      另一种方法是使用数字表(如果您还没有数字表,也可以自行创建)。假设您不能提供超过 255 剂:

      DECLARE @Doses table 
      (
          RowID          int IDENTITY(1,1),
          DateShipped    date,
          RemainingDoses tinyint,
          RXDays         tinyint
      );
      
      INSERT @Doses(DateShipped, RemainingDoses, RXDays)
        VALUES('20190605',2,30),('20190704',3,24);
      
      -- pseudo Numbers table
      DECLARE @num table(n tinyint);
      
      INSERT @num(n) SELECT TOP (256) 
             row_number() OVER (ORDER BY (SELECT NULL)) - 1 
        FROM sys.all_columns;
      
      
      SELECT d.RowID, d.DateShipped, d.RemainingDoses, d.RXDays,
          SubsequentShipdate = DATEADD(DAY, n.n*d.RXDays, d.DateShipped) 
        FROM @Doses AS d
        INNER JOIN @num AS n
        ON n.n <= d.RemainingDoses
        ORDER BY d.RowID, SubsequentShipdate;
      

      结果:

      如果您只想要“下一个”日期而不包括原始行,只需添加:

      AND n.n > 0
      

      或者,不要在数字表中包含0(尽管它可能很有用):

      INSERT @num(n) SELECT TOP (255) 
             row_number() OVER (ORDER BY (SELECT NULL)) 
      

      【讨论】:

      • 这是一种非常棒的方法,也是一种不必使用 CTE 的方法,谢谢@Aaron
      猜你喜欢
      • 1970-01-01
      • 2013-10-26
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 2017-07-11
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      相关资源
      最近更新 更多