在 SQL Server 2008 中计算到期日期

Posted

技术标签:

【中文标题】在 SQL Server 2008 中计算到期日期【英文标题】:Calculate Maturity date in SQL Server 2008 【发布时间】:2017-10-16 10:08:54 【问题描述】:

第一期的日期是加入日期。客户必须分期付款 10 次。每个月的每一期。因此,11 个月后,客户有资格以节省的金额购买产品。因此,到期日为加入日期后的 11 个月。 加入日期示例:2016 年 9 月 12 日 到期日:2017 年 7 月 12 日

如果客户在预定日期或当月到期日的任何一天付款,请不要延长到期日,否则到期日会延长。

Scenario 1: Pays on time
------------------------

Joining date: 12/Sep/2016
Expected output: 12/Jul/2017
加入日期 2016 年 9 月 12 日 Inst 没有付款日期 实际付款日期 考虑月份 1 2016 年 9 月 12 日 2016 年 9 月 12 日 2016 年 9 月 2 2016 年 10 月 5 日 2016 年 10 月 12 日 2016 年 10 月 3 2016 年 11 月 21 日 2016 年 11 月 12 日 2016 年 11 月 4 2016 年 12 月 12 日 2016 年 12 月 12 日 2016 年 12 月 5 2017 年 1 月 2 日 2017 年 1 月 12 日 2017 年 1 月 6 2017 年 2 月 2 日 2017 年 2 月 12 日 2017 年 2 月 7 2017 年 3 月 6 日 2017 年 3 月 12 日 2017 年 3 月 8 2017 年 4 月 6 日 2017 年 4 月 12 日 2017 年 4 月 9 2017 年 5 月 1 日 2017 年 5 月 12 日 2017 年 5 月 10 2017 年 6 月 7 日 2017 年 6 月 12 日 2017 年 6 月 到期日 2017 年 7 月 12 日

Scenario1

Scenario 2: when payments paid with delay
-----------------------------------------

Joining date: 12/Sep/2016
Expected output: 12/Sep/2017

Scenario2

 加入日期 12/Sep/2016

Inst 没有付款日期 实际日期 考虑付款月份
1 2016 年 9 月 12 日 2016 年 9 月 12 日 2016 年 9 月
2 2016 年 10 月 5 日 2016 年 10 月 12 日 2016 年 10 月
3 2016 年 11 月 21 日 2016 年 11 月 12 日 2016 年 11 月
4 2017 年 2 月 2 日 2016 年 12 月 12 日 2017 年 2 月
5 2017 年 2 月 2 日 2017 年 1 月 12 日 2017 年 3 月
6 2017 年 3 月 6 日 2017 年 2 月 12 日 2017 年 4 月
7 2017 年 3 月 6 日 2017 年 3 月 12 日 2017 年 5 月
8 2017 年 6 月 1 日 2017 年 4 月 12 日 2017 年 6 月
9 2017 年 6 月 1 日 2017 年 5 月 12 日 2017 年 7 月
10 2017 年 8 月 7 日 2017 年 6 月 12 日 2017 年 8 月

        到期日 2017 年 9 月 12 日

【问题讨论】:

使用表结构和示例数据发布 SQL 将帮助我们获得解决方案,更详细的规则描述会有所帮助,据我所知,该规则似乎适用于每个月的错过付款延长一个月。 【参考方案1】:

您的问题不清楚您要达到的目标。但是,我从你的两个例子中了解到,到期日应该与分期付款延迟一样多的月份。

甚至您的 Fiddler 场景也不清楚。有了这个小小的了解,我想出了下面的T-SQL来解决你的问题:

-- Schema generation
CREATE TABLE [dbo].[Payment](
    [InsNo] [int] PRIMARY KEY NOT NULL,
    [ReceiptDate] [datetime] NULL,
    [ScheduledDate] [datetime] NULL,
    [ConsideredMonth] DATETIME NULL,
) ON [PRIMARY]

GO

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(1, '2016-09-12 00:00:00', '2016-09-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(2, '2016-10-05 00:00:00', '2016-10-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(3, '2016-11-21 00:00:00', '2016-11-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(4, '2017-02-02 00:00:00', '2016-12-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(5, '2017-02-02 00:00:00', '2016-01-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(6, '2017-02-02 00:00:00', '2016-02-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(7, '2017-03-06 00:00:00', '2016-03-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(8, '2017-03-06 00:00:00', '2016-04-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(9, '2017-06-01 00:00:00', '2016-05-12 00:00:00');

INSERT INTO [Payment]([InsNo], [ReceiptDate], [ScheduledDate]) 
    VALUES(10, '2017-06-01 00:00:00', '2016-06-12 00:00:00');

GO

--   Solution using Cursor          
DECLARE @receiptDate DATETIME
        ,@lastInstForDate DATETIME
DECLARE @insNo INT

DECLARE _paymentsCursor CURSOR FAST_FORWARD
FOR
    SELECT p.InsNo
            ,p.ReceiptDate
    FROM   Payment p
    ORDER BY
            p.InsNo

OPEN _paymentsCursor

FETCH NEXT FROM _paymentsCursor INTO
    @insNo, @receiptDate
WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @lastInstForDate = p.ConsideredMonth
    FROM   Payment p
    WHERE  p.InsNo = @insNo - 1

    IF DATEADD(MONTH ,1 ,@lastInstForDate) > @receiptDate
        UPDATE Payment
        SET ConsideredMonth      = DATEADD(MONTH ,1 ,@lastInstForDate)
        WHERE InsNo = @insNo
    ELSE
        UPDATE Payment
        SET    ConsideredMonth = CAST(CAST(YEAR(ReceiptDate) AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(ReceiptDate) AS VARCHAR(2)) ,2) + '01' AS DATETIME)
        WHERE  InsNo = @insNo

    FETCH NEXT FROM _paymentsCursor INTO
        @insNo, @receiptDate
END

CLOSE _paymentsCursor
DEALLOCATE _paymentsCursor


DECLARE @lastPaymentDate DATETIME

DECLARE @maturityDate DATETIME
SELECT @maturityDate = DATEADD(month, 1, MAX(p.ConsideredMonth)), @lastPaymentDate = MAX(p.ReceiptDate) FROM dbo.Payment p
SET @maturityDate = CAST(CAST(YEAR(@maturityDate) AS VARCHAR(4)) + RIGHT('0' + CAST(MONTH(@maturityDate) AS VARCHAR(2)) ,2) + RIGHT('0' + CAST(DAY(@lastPaymentDate) AS VARCHAR(2)) ,2) AS DATETIME)
SET @maturityDate = DATEADD(DAY, 1, @maturityDate)

SELECT @maturityDate

【讨论】:

【参考方案2】:

试试这个 -

SELECT MATURITY_DATE = CASE WHEN MAX([ReceiptDate]) <= DATEADD (MM , 9, '2016-09-12 00:00:00')
                       THEN DATEADD (MM , 10, '2016-09-12 00:00:00')
                       ELSE DATEADD (MM , 2, MAX([ReceiptDate])) END
FROM [dbo].[Payment];

【讨论】:

【参考方案3】:

你可以使用这个公式。

select  DATEADD(DAY, 
                DATEPART(DAY,(MIN([Actual Date]))) - DATEPART(DAY,(MAX([Payment Date]))),
                    DATEADD(MONTH, 
                        ( 11 - COUNT(*) )
                        , MAX([Payment Date])) )
from @InstalmentTable

【讨论】:

以上是关于在 SQL Server 2008 中计算到期日期的主要内容,如果未能解决你的问题,请参考以下文章

sql 获取SQL Server许可证到期日期

SQL Server 2008 仅在月份和年份之间选择数据

需要在 SQL Server 2008 中查找两个日期之间的日期

在 SQL Server 2008 R2 和 SQL Server Compact 4 中存储日期/时间数据的最佳方式

SQL sever 2008 如何根据一个表中的两个时间计算出时间差

如何仅从 sql server 2008 中的日期中提取年份?