如何按月开始和结束细分时间政策生命周期

时间:2016-06-02 16:54:25

标签: sql datetime reporting-services

Picture. Need to be like that

我需要按月分解每个政策生命周期。从政策开始到该月末,然后从开始到下个月结束,并且对于每个时间段需要计算天数,因此我可以计算每个政策的收入溢价。

请看图片我需要做些什么。

[DECLARE @EarnedToDate datetime ='2016-06-30'
;WITH  Cte_Policies AS 
        (
        SELECT 
            PolicyNumber
            ,TransactionEffectiveDate
            ,TransactionExpirationDate 
            ,WrittenPremium
            ,DATEDIFF(DAY,TransactionEffectiveDate,TransactionExpirationDate) AS TotalDays 
            ,CASE 
                WHEN TransactionEffectiveDate> @EarnedToDate    THEN 0       --Policy not yet in effect 
                WHEN TransactionExpirationDate< @EarnedToDate   THEN DATEDIFF(DAY,TransactionEffectiveDate,TransactionExpirationDate) 
                ELSE DATEDIFF(DAY,TransactionEffectiveDate,@EarnedToDate)
            END AS EarnedDays
            ,CASE 
                WHEN TransactionEffectiveDate > @EarnedToDate THEN DATEDIFF(DAY,TransactionEffectiveDate,TransactionExpirationDate) 
                WHEN TransactionExpirationDate < @EarnedToDate THEN 0 -- Policy completed 
                ELSE DATEDIFF(DAY,@EarnedToDate,TransactionExpirationDate)
            END AS UnearnedDays         
        FROM ##TempTable1
        )
SELECT PolicyNumber,
        TransactionEffectiveDate as TransactionEffectiveDate,
        TransactionExpirationDate as TransactionExpirationDate
        --WrittenPremium/TotalDays AS DayPremium,
        ,SUM(CASE WHEN EarnedDays   = 0 THEN 0 ELSE WrittenPremium/TotalDays * EarnedDays END) AS EarnedPremium
        ,SUM(CASE WHEN UnearnedDays = 0 THEN 0 ELSE WrittenPremium/TotalDays * UnearnedDays END) AS UnearnedPremium

FROM 
    Cte_Policies where PolicyNumber ='PACA1000238-02'
GROUP BY 
        TransactionEffectiveDate 
        ,TransactionExpirationDate 
        --,WrittenPremium/TotalDays
        ,PolicyNumber][1]

3 个答案:

答案 0 :(得分:0)

正如我在你的推文中所想,这对代码来说非常简单,但需要做一些工作才能理解。

WITH raw_data AS (
    SELECT
        Cast(text_TransactionEffectiveDate AS DATE) AS TransactionEffectiveDate
,       Cast(text_TransactionExpirationDate AS DATE) AS TransactionExpirationDate
        FROM (VALUES
            ('1953-01-15', '1992-02-23')
,           ('2012-08-12', '2012-08-26')
            ) AS z (text_TransactionEffectiveDate, text_TransactionExpirationDate )
), policy_dates AS (
SELECT
    raw_data.*
,   DateAdd(month, DateDiff(month, '1753-01-01', TransactionEffectiveDate), '1753-01-01') AS Policy_Start
,   DateAdd(month, DateDiff(month, '1753-01-01', TransactionExpirationDate), '1753-02-01') AS Policy_Expired
    FROM raw_data
)
SELECT DateDiff(day, Policy_start, Policy_Expired) AS Policy_days, *
   FROM policy_dates

这是保险领域常见的计算。诀窍在于计算有效月的开始和到期月的开始(在策略结束之后)。诀窍是,使用的时间比其他人(1753-02-01)晚一个月。

-PatP

答案 1 :(得分:0)

添加一个或两个CTE,将策略生效和到期日期分为不同月份,然后重复使用现有代码/ CTE

请务必查看EarnedDays和UnearnedDays的所有边界条件,并确保它们符合您的业务规则

DECLARE @EarnedToDate DATETIME 
SET @EarnedToDate = '2016-06-30'

DECLARE @tblPolicies TABLE
(
    PolicyNumber VARCHAR(100)
    , PolicyEffectiveDate DATETIME
    , PolicyExpirationDate DATETIME 
    , WP MONEY  --WrittenPremium
) 

DECLARE @tblPolicyMonths TABLE
(
    PolicyNumber VARCHAR(100),
    MonthStart DATETIME,
    MonthEnd DATETIME
)

DECLARE @CurPos INT
SET @CurPos = 1
WHILE @CurPos < 4000
    BEGIN
        --Create a bunch of policies
        INSERT INTO @tblPolicies
            SELECT 'P' + CONVERT(varchar, @CurPos), DATEADD(d, @CurPos,     GETDATE()), DATEADD(YY, 1, DATEADD(d, @CurPos, GETDATE())), @CurPos

        SET @CurPos = @CurPos + 1
    END

DECLARE @LastPolicyDate DATETIME
SET @LastPolicyDate = (SELECT MAX(PolicyExpirationDate) FROM @tblPolicies)

;WITH Cte_All_Dates AS
(
    SELECT MIN(PolicyEffectiveDate) DateValue
        FROM @tblPolicies
       UNION ALL
       SELECT DateValue + 1
       FROM    Cte_All_Dates 
       WHERE   DateValue + 1 < = @LastPolicyDate
)
INSERT INTO @tblPolicyMonths
    SELECT P.PolicyNumber   
        ,MIN(DateValue)
        ,MAX(DateValue)
        FROM Cte_All_Dates PD
            INNER JOIN @tblPolicies P
                ON CONVERT(DATE, PD.DateValue) BETWEEN P.PolicyEffectiveDate    AND P.PolicyExpirationDate
        GROUP BY P.PolicyNumber
            , DATEPART(MM, DateValue)
            , DATEPART(YY, DateValue)
OPTION (MAXRECURSION 32767);

SELECT 
        P.PolicyNumber
        ,CONVERT(DATE, MonthStart) As StartRiskMonth
        ,CONVERT(DATE, MonthEnd) AS EndRiskMonth
        ,WP as WrittenPremium
        ,DATEDIFF(DAY,MonthStart,MonthEnd)+1 AS TotalDays 
        ,CASE 
            WHEN MonthStart > @EarnedToDate THEN 0       --Policy not yet in     effect 
            WHEN MonthEnd < @EarnedToDate THEN     DATEDIFF(DAY,MonthStart,MonthEnd)+1 
            ELSE DATEDIFF(DAY,MonthStart,@EarnedToDate)+1
        END AS EarnedDays
        ,CASE 
            WHEN MonthStart > @EarnedToDate THEN     DATEDIFF(DAY,MonthStart,MonthEnd)+1
            WHEN MonthEnd < @EarnedToDate THEN 0 -- Policy completed 
            ELSE DATEDIFF(DAY,@EarnedToDate,MonthEnd)
        END AS UnearnedDays
        , @EarnedToDate AS 'EarnedToDate'
    FROM @tblPolicyMonths PM
        INNER JOIN @tblPolicies P
            ON PM.PolicyNumber = P.PolicyNumber
    ORDER BY PolicyNumber, MonthStart, MonthEnd

答案 2 :(得分:0)

我的原始片段在Twitter上回答了您的问题,但是下面的代码片段更进一步,并在StackOverflow上提供了您问题中指定的结果集...

; WITH Earned_to_date AS (
   SELECT Cast('2016-07-01' AS DATE) AS Earned_to_date
), policy_data AS (
    SELECT
        policy_number
,       Cast(text_Effective  AS DATE) AS TransactionEffectiveDate
,       Cast(text_Expiration AS DATE) AS TransactionExpirationDate
,       policy_premium
        FROM (VALUES
            ('p1', '1993-01-01', '1994-12-31', 940.00)
,           ('p3', '2011-12-01', '2012-05-31', 485.00)
,           ('p5', '2011-12-16', '2012-05-15', 485.00)
,           ('p7', '2015-12-16', '2016-11-15', 485.00)
            ) AS z (policy_number, text_Effective
,                text_Expiration, policy_premium)
), digits AS (
SELECT digit
   FROM (VALUES (0), (1), (2), (3), (4)
,      (5), (6), (7), (8), (9)) AS z2 (digit)
), numbers AS (
SELECT 1000 * d4.digit + 100 * d3.digit + 10 * d2.digit + d1.digit AS number
    FROM digits AS d1
    CROSS JOIN digits AS d2
    CROSS JOIN digits AS d3
    CROSS JOIN digits AS d4
), calendar AS (
SELECT
    DateAdd(month, number, '1753-01-01') AS month_of
,   DateAdd(month, number, '1753-02-01') AS month_after
    FROM numbers
), policy_dates AS (
SELECT
    policy_number
,   CASE
        WHEN month_of < TransactionEffectiveDate THEN TransactionEffectiveDate
        ELSE month_of
    END AS StartRiskMonth
,   CASE
       WHEN TransactionExpirationDate < month_after THEN TransactionExpirationDate
       WHEN Earned_to_date.Earned_to_date < month_after THEN Earned_to_date
       ELSE month_after
    END AS EndRiskMonth
,   DateDiff(day, TransactionEffectiveDate, TransactionExpirationDate) AS policy_days
,   policy_premium
    FROM policy_data
    JOIN calendar
        ON (policy_data.TransactionEffectiveDate < calendar.month_after
        AND calendar.month_of < policy_data.TransactionExpirationDate)
    CROSS JOIN Earned_to_date
    WHERE  month_of < Earned_to_date
)
SELECT policy_number, StartRiskMonth, EndRiskMonth
,   DateDiff(day, StartRiskMonth, EndRiskMonth) AS DaysInMonth
,   policy_premium * DateDiff(day, StartRiskMonth, EndRiskMonth) / policy_days
    FROM policy_dates
    ORDER BY policy_number, StartRiskMonth