如何获得 SQL 中周期性月份的最后一天?
How can I get the last day of periodic months in SQL?
我正在根据我写的查询中给定的值准备下一个 5 个月的日期。
DECLARE @StartDate DATETIME = '2022-03-31', @monthadd INT = 5;
; WITH dates AS (
SELECT @StartDate [vade]
UNION ALL
SELECT DATEADD(MONTH,1,[vade])
FROM dates
WHERE DATEADD(MONTH,1,[vade]) <= DATEADD(MONTH,@monthadd,@StartDate)
)
SELECT *
FROM dates
OPTION (MAXRECURSION 0)
GO
但是,当月的最后一天为31时,需要列出后面月份的最后一天,也就是最近的一天。我该怎么做?
实际结果
vade
2022-03-31 00:00:00.000
2022-04-30 00:00:00.000
2022-05-30 00:00:00.000
2022-06-30 00:00:00.000
2022-07-30 00:00:00.000
2022-08-30 00:00:00.000
编辑:
这是一个成熟度计划。如果此人在每月 31 日分期付款,则必须在每个月的最后一天付款。如果他在30日做,这个月有30天就应该有30天,有31天就应该有30天,有29天就应该有29天。如果从 20 日开始到期,则必须是每个月的 20 日。假设您在当月 30 号贷款。如果月份是29天,他们会要求你在第29天付款,如果月份是31天,他们会要求你在第30天付款。我知道这很令人困惑,我对此感到抱歉。
2022-04-01 更新
如果我没理解错的话,您想 return 每个月的“日期”相同 - 除了 @StartDate 是该月的最后一天.
一种方法是确定@StartDate 是否是该月的最后一天。如果是这样,请使用 EOMONTH() 到 return 随后每个月的最后一天。否则,使用 DATEADD() return 每个月指定的“天”。这种方法适用于任何日期。
一种方法如下:
- 如果到期日是一个月的最后一天,或者到期日月是 > 下个月的天数,使用EOMONTH()到return该月的最后一天
- 否则,使用 DATEADD() 和 DATEFROMPARTS() 使用月度 日 的到期日
生成下一个日期
SQL:
-- Note: Using 12 months for demo only
; WITH dates AS (
SELECT @StartDate AS MaturityDate
, IIF(@StartDate = EOMONTH(@StartDate), 1, 0) AS IsEOM
UNION ALL
SELECT
CASE -- Maturity date is last day of month OR
-- Maturity "day" is > number of days in current month
WHEN IsEOM = 1 OR DAY(@StartDate) > DAY( EOMONTH(NextMaturityDate) )
THEN EOMONTH( DATEADD(MONTH, 1, MaturityDate ))
-- Otherwise, maturity "day" is valid for current month
ELSE DATEFROMPARTS(
Year(NextMaturityDate)
, Month(NextMaturityDate)
, DAY(@StartDate)
)
END
, IsEOM
FROM ( SELECT MaturityDate
, IsEOM
, DATEADD(MONTH, 1, MaturityDate) AS NextMaturityDate
FROM dates
) t
WHERE MaturityDate < @EndDate
)
SELECT MaturityDate AS [vade]
FROM dates
OPTION (MAXRECURSION 0)
2022-03-31 的结果 (每月最后一天)
vade
2022-03-31
2022-04-30
2022-05-31
2022-06-30
2022-07-31
2022-08-31
2022-09-30
2022-10-31
2022-11-30
2022-12-31
2023-01-31
2023-02-28
2023-03-31
2023-04-30
2023-05-31
2023-06-30
2022 年 3 月 30 日的结果 (不是月份的最后一天)
vade
2022-03-30
2022-04-30
2022-05-30
2022-06-30
2022-07-30
2022-08-30
2022-09-30
2022-10-30
2022-11-30
2022-12-30
2023-01-30
2023-02-28
2023-03-30
2023-04-30
2023-05-30
2023-06-30
db<>fiddle here
DATEADD
function已经考虑到了月末等极端情况,所以你不需要处理。
为了拥有更简洁的代码,您可以放置一个 stored procedure
,创建(或替换)一个 dates_list
table,然后循环数月以添加到开始日期。
DELIMITER //
CREATE OR REPLACE PROCEDURE create_dates_list (
IN start_date DATETIME,
IN num_months INT
)
BEGIN
DECLARE idx INT DEFAULT 0;
CREATE OR REPLACE TABLE dates_list (
date DATE
);
WHILE idx <> num_months DO
INSERT INTO tab VALUES(
DATEADD(@start_date, INTERVAL @idx MONTH)
);
SET idx = idx + 1;
END WHILE;
END //
DELIMITER ;
当您需要获取新的日期时,您可以通过设置参数和调用存储过程来刷新table:
DECLARE @StartDate DATETIME = '2022-03-31', @monthadd INT = 5;
CALL create_dates_list(@StartDate, @monthadd);
您可以随时使用 sql 赋予您的工具自由访问 table。
如果您不需要 table 用于进一步的会话,您可以将 table 定义为 TEMPORARY
。临时 table 上的 official documentation 示例非常详细和全面,请查看以了解更多信息。
我正在根据我写的查询中给定的值准备下一个 5 个月的日期。
DECLARE @StartDate DATETIME = '2022-03-31', @monthadd INT = 5;
; WITH dates AS (
SELECT @StartDate [vade]
UNION ALL
SELECT DATEADD(MONTH,1,[vade])
FROM dates
WHERE DATEADD(MONTH,1,[vade]) <= DATEADD(MONTH,@monthadd,@StartDate)
)
SELECT *
FROM dates
OPTION (MAXRECURSION 0)
GO
但是,当月的最后一天为31时,需要列出后面月份的最后一天,也就是最近的一天。我该怎么做?
实际结果
vade |
---|
2022-03-31 00:00:00.000 |
2022-04-30 00:00:00.000 |
2022-05-30 00:00:00.000 |
2022-06-30 00:00:00.000 |
2022-07-30 00:00:00.000 |
2022-08-30 00:00:00.000 |
编辑:
这是一个成熟度计划。如果此人在每月 31 日分期付款,则必须在每个月的最后一天付款。如果他在30日做,这个月有30天就应该有30天,有31天就应该有30天,有29天就应该有29天。如果从 20 日开始到期,则必须是每个月的 20 日。假设您在当月 30 号贷款。如果月份是29天,他们会要求你在第29天付款,如果月份是31天,他们会要求你在第30天付款。我知道这很令人困惑,我对此感到抱歉。
2022-04-01 更新
如果我没理解错的话,您想 return 每个月的“日期”相同 - 除了 @StartDate 是该月的最后一天.
一种方法是确定@StartDate 是否是该月的最后一天。如果是这样,请使用 EOMONTH() 到 return 随后每个月的最后一天。否则,使用 DATEADD() return 每个月指定的“天”。这种方法适用于任何日期。
一种方法如下:
- 如果到期日是一个月的最后一天,或者到期日月是 > 下个月的天数,使用EOMONTH()到return该月的最后一天
- 否则,使用 DATEADD() 和 DATEFROMPARTS() 使用月度 日 的到期日 生成下一个日期
SQL:
-- Note: Using 12 months for demo only
; WITH dates AS (
SELECT @StartDate AS MaturityDate
, IIF(@StartDate = EOMONTH(@StartDate), 1, 0) AS IsEOM
UNION ALL
SELECT
CASE -- Maturity date is last day of month OR
-- Maturity "day" is > number of days in current month
WHEN IsEOM = 1 OR DAY(@StartDate) > DAY( EOMONTH(NextMaturityDate) )
THEN EOMONTH( DATEADD(MONTH, 1, MaturityDate ))
-- Otherwise, maturity "day" is valid for current month
ELSE DATEFROMPARTS(
Year(NextMaturityDate)
, Month(NextMaturityDate)
, DAY(@StartDate)
)
END
, IsEOM
FROM ( SELECT MaturityDate
, IsEOM
, DATEADD(MONTH, 1, MaturityDate) AS NextMaturityDate
FROM dates
) t
WHERE MaturityDate < @EndDate
)
SELECT MaturityDate AS [vade]
FROM dates
OPTION (MAXRECURSION 0)
2022-03-31 的结果 (每月最后一天)
vade |
---|
2022-03-31 |
2022-04-30 |
2022-05-31 |
2022-06-30 |
2022-07-31 |
2022-08-31 |
2022-09-30 |
2022-10-31 |
2022-11-30 |
2022-12-31 |
2023-01-31 |
2023-02-28 |
2023-03-31 |
2023-04-30 |
2023-05-31 |
2023-06-30 |
2022 年 3 月 30 日的结果 (不是月份的最后一天)
vade |
---|
2022-03-30 |
2022-04-30 |
2022-05-30 |
2022-06-30 |
2022-07-30 |
2022-08-30 |
2022-09-30 |
2022-10-30 |
2022-11-30 |
2022-12-30 |
2023-01-30 |
2023-02-28 |
2023-03-30 |
2023-04-30 |
2023-05-30 |
2023-06-30 |
db<>fiddle here
DATEADD
function已经考虑到了月末等极端情况,所以你不需要处理。
为了拥有更简洁的代码,您可以放置一个 stored procedure
,创建(或替换)一个 dates_list
table,然后循环数月以添加到开始日期。
DELIMITER //
CREATE OR REPLACE PROCEDURE create_dates_list (
IN start_date DATETIME,
IN num_months INT
)
BEGIN
DECLARE idx INT DEFAULT 0;
CREATE OR REPLACE TABLE dates_list (
date DATE
);
WHILE idx <> num_months DO
INSERT INTO tab VALUES(
DATEADD(@start_date, INTERVAL @idx MONTH)
);
SET idx = idx + 1;
END WHILE;
END //
DELIMITER ;
当您需要获取新的日期时,您可以通过设置参数和调用存储过程来刷新table:
DECLARE @StartDate DATETIME = '2022-03-31', @monthadd INT = 5;
CALL create_dates_list(@StartDate, @monthadd);
您可以随时使用 sql 赋予您的工具自由访问 table。
如果您不需要 table 用于进一步的会话,您可以将 table 定义为 TEMPORARY
。临时 table 上的 official documentation 示例非常详细和全面,请查看以了解更多信息。