如何在1月30日或1月31日增加1个月,在2月之后分别增加3月30日或3月31日

时间:2020-05-27 11:31:41

标签: sql-server

我正面临这个问题,今天花了很多时间。所以,我想在这里分享它:

我有一个存储 debitDate 的表,并且有一个存储过程,每个月我们在表中将借记日期设置为下个月。

因此,如果其借记日期为29th Jan, 2020 -> 29th Feb, 2020 -> 29th March, 2020-则应这样进行。我正在存储过程中使用DATEADD()函数。

但是在30日和31日,我面临问题。在未来的几年中,它应该像下面这样工作:

期望的行为

30th Jan, 2020 -> 29th Feb, 2020 -> 30th Mar, 2020 -> 30th Apr, 2020

30th Jan, 2021 -> 28th Feb, 2021 -> 30th Mar, 2021 -> 30th Apr, 2021

31st Jan, 2020 -> 29th Feb, 2020 -> 31st Mar, 2020 -> 30th Apr, 2020

问题

30th Jan, 2020 -> 29th Feb, 2020 -> 29th Mar, 2020 -> 29th Apr, 2020

30th Jan, 2021 -> 28th Feb, 2021 -> 28th Mar, 2021 -> 28th Apr, 2021

31st Jan, 2020 -> 29th Feb, 2020 -> 29th Mar, 2020 -> 29th Apr, 2020

2 个答案:

答案 0 :(得分:1)

解决方案1 ​​

对于解决方案,我认为我可以在表中添加一个新列作为 previousDebitDate ,并且当我们更新借记日期时,我们将检查上一个DebitDate日是30还是31。 如果为true,则

DATEADD(MONTH, 2, @previousDebitDate)

其他

DATEADD(MONTH, 1, @debitDate)

如果有人有更好的解决方案,请随时发布您的答案。

解决方案2

对于此问题,更好的解决方案是将 debitDay 作为新列添加到表中,并仅保存日部分(例如30)并即时计算每个月的借记日期。

我认为解决方案2更好!谢谢@Arvo !!!

答案 1 :(得分:0)

也许我已经非常了解,也许不是,但是这就是我在寻找的东西

CREATE TABLE Data
(
  Dates DATE
);

INSERT Data(Dates) VALUES
('2020-01-30');
WITH CTE AS
(
  SELECT Dates, 
         DATEADD(Month, 1, Dates) NextMonth, 
         DAY(EOMONTH(DATEADD(Month, 1, Dates))) LastDay
  FROM Data
  UNION ALL
  SELECT DATEADD(Month, 1, Dates),
         DATEADD(Month, 1, NextMonth),
         DAY(EOMONTH(DATEADD(Month, 1, NextMonth)))
  FROM CTE
  WHERE Dates <= '2021-12-31'
)
SELECT Dates, NextMonth, DATEFROMPARTS(YEAR(Dates), MONTH(NextMonth),
              CASE WHEN LastDay > 30 THEN 30 ELSE LastDay END) Value
FROM CTE;

哪个会返回:

+------------+------------+------------+
|   Dates    | NextMonth  |   Value    |
+------------+------------+------------+
| 2020-01-30 | 2020-02-29 | 2020-02-29 |
| 2020-02-29 | 2020-03-29 | 2020-03-30 |
| 2020-03-29 | 2020-04-29 | 2020-04-30 |
| 2020-04-29 | 2020-05-29 | 2020-05-30 |
| 2020-05-29 | 2020-06-29 | 2020-06-30 |
| 2020-06-29 | 2020-07-29 | 2020-07-30 |
| 2020-07-29 | 2020-08-29 | 2020-08-30 |
| 2020-08-29 | 2020-09-29 | 2020-09-30 |
| 2020-09-29 | 2020-10-29 | 2020-10-30 |
| 2020-10-29 | 2020-11-29 | 2020-11-30 |
| 2020-11-29 | 2020-12-29 | 2020-12-30 |
| 2020-12-29 | 2021-01-29 | 2020-01-30 |
| 2021-01-29 | 2021-02-28 | 2021-02-28 |
| 2021-02-28 | 2021-03-28 | 2021-03-30 |
| 2021-03-28 | 2021-04-28 | 2021-04-30 |
| 2021-04-28 | 2021-05-28 | 2021-05-30 |
| 2021-05-28 | 2021-06-28 | 2021-06-30 |
| 2021-06-28 | 2021-07-28 | 2021-07-30 |
| 2021-07-28 | 2021-08-28 | 2021-08-30 |
| 2021-08-28 | 2021-09-28 | 2021-09-30 |
| 2021-09-28 | 2021-10-28 | 2021-10-30 |
| 2021-10-28 | 2021-11-28 | 2021-11-30 |
| 2021-11-28 | 2021-12-28 | 2021-12-30 |
| 2021-12-28 | 2022-01-28 | 2021-01-30 |
| 2022-01-28 | 2022-02-28 | 2022-02-28 |
+------------+------------+------------+

好多了

WITH CTE AS
(
  SELECT 1 N, Dates, Dates ExpectedValue
  FROM Data
  UNION ALL
  SELECT N+1, DATEADD(Month, 1, Dates), DATEFROMPARTS(YEAR(ExpectedValue), MONTH(DATEADD(Month, 1, ExpectedValue)), 
               CASE WHEN DAY(EOMONTH(DATEADD(Month, 1, ExpectedValue))) > 30 THEN 30
                    ELSE DAY(EOMONTH(DATEADD(Month, 1, ExpectedValue)))
               END)
  FROM CTE
  WHERE N < 15
)
SELECT *
FROM CTE
ORDER BY N;

返回:

+----+------------+---------------+
| N  |   Dates    | ExpectedValue |
+----+------------+---------------+
|  1 | 2020-01-30 | 2020-01-30    |
|  2 | 2020-02-29 | 2020-02-29    |
|  3 | 2020-03-29 | 2020-03-30    |
|  4 | 2020-04-29 | 2020-04-30    |
|  5 | 2020-05-29 | 2020-05-30    |
|  6 | 2020-06-29 | 2020-06-30    |
|  7 | 2020-07-29 | 2020-07-30    |
|  8 | 2020-08-29 | 2020-08-30    |
|  9 | 2020-09-29 | 2020-09-30    |
| 10 | 2020-10-29 | 2020-10-30    |
| 11 | 2020-11-29 | 2020-11-30    |
| 12 | 2020-12-29 | 2020-12-30    |
| 13 | 2021-01-29 | 2020-01-30    |
| 14 | 2021-02-28 | 2020-02-29    |
| 15 | 2021-03-28 | 2020-03-30    |
+----+------------+---------------+

这里是db<>fiddle