结算周期日期范围

时间:2018-01-03 21:47:41

标签: sql sql-server tsql date sql-server-2012

代码:

DECLARE @CurrentDate DATE = '2018-01-02' ;  -- Can be any date. This is just a date I used as an anchor point.
DECLARE @BillingDayOfMonth INT = 31 ;       -- The day of the billing every month (can be between 1st and 31st of the month).

;WITH [TT1] ( [N] ) AS
    (
        SELECT  1
        UNION ALL
        SELECT  1
    )
    , [TT2] ( [N] ) AS
    (
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
    )
    , [TT] ( [N] ) AS
    (
        SELECT      ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) )
        FROM        [TT1] [T1]
        CROSS JOIN  [TT2] [T2]
    )
SELECT  [N]
FROM    [TT] ; -- This gives me the count of 12 cycles (can vary).

目标: 返回前一个结算周期日期的当前和X个数字(上例中总计12个周期)。

如果BillingDayOfMonth在一个月内不存在(即29日至31日,具体取决于月份),请选择该月的最后一天作为BillingDayOfMonth。因此,如果BillingDayOfMonth = 31st,那么这一天在11月就不存在了。所以周期将从@ 11/30而不是11/31开始。上述代码不完整,需要您的帮助才能找到有效的解决方案。谢谢

期望的输出:

CycleStartDate  CycleEndDate
2017-12-31      2018-01-30      -- The most current cycle
2017-11-30      2017-12-30
2017-10-31      2017-11-29
2017-09-30      2017-10-30
2017-08-31      2017-09-29
2017-07-31      2017-08-30
2017-06-30      2017-07-30
2017-05-31      2017-06-29
2017-04-30      2017-05-30      -- Notice the EndDate
2017-03-31      2017-04-29      -- Notice the EndDate
2017-02-28      2017-03-30      -- Notice the StartDate
2017-01-31      2017-02-27      -- Notice the EndDate

1 个答案:

答案 0 :(得分:1)

因此,根据您的数字表格方法和规则,您可以使用如下的查询。

我测试了这个@BillingDayOfMonth值,如25,28,30,并且发现结果合理正确。

See live demo

DECLARE @CurrentDate DATE = '2018-01-02' ;  -- Can be any date. This is just a date I used as an anchor point.
DECLARE @BillingDayOfMonth INT = 31 ;       -- The day of the billing every month (can be between 1st and 31st of the month).
DECLARE @StartDate DATE
SET @StartDate=   CASE WHEN 
                       DAY(EOMONTH(@CurrentDate)) < @BillingDayOfMonth
                       THEN
                       EOMONTH(@CurrentDate)
                       ELSE
                       DATEFROMPARTS(YEAR(@CurrentDate),MONTH(@CurrentDate),@BillingDayOfMonth)
                   END

;WITH [TT1] ( [N] ) AS
    (
        SELECT  1
        UNION ALL
        SELECT  1
    )
    , [TT2] ( [N] ) AS
    (
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
        UNION ALL
        SELECT  1
    )
    , [TT] ( [N] ) AS
    (
        SELECT    
        ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) )

        FROM        [TT1] [T1]
        CROSS JOIN  [TT2] [T2]
    )

SELECT  CycleStartDate  = 
                    DATEADD(M,-N,@StartDate)
        ,
        CycleEndDate    =
                    DATEADD(D,-1,DATEADD(M,1-N,@StartDate))

FROM    [TT] ;