如何计算直到@AsOfDate 的两个日期之间的已赚保费,并在 DAX 中按月细分
How to calculate Earned Premium between two dates till @AsOfDate and break it down by each month in DAX
我有保费 TransactionEffectiveDate
和 TransactionExpirationDate
。
是否有任何方法可以在 DAX 中编写查询,该查询将获取每个保费金额并将其按这两个日期之间的月份进行细分。
@AsOfDate 参数将是政策停止收入的日期。
例如:
PolicyNumber WIC1000158-00
保费为 $82,913
和 TransactionEffectiveDate 1/5/2018
和TransactionExpirationDate 1/5/2019.
这给了我们总共 365 天的保单寿命。
让我们看看我们在 '06/29/2018' 之前赚了多少钱
因此 82,913 的保费应按 12 个月细分:
所以第一个保单月我们只有 27 天
所以 82,913/365 * 27 = 6,133.29 - 这就是第一个月的收入。
以此类推,直到@AsOfDate
。
结果应该像 @AsOfDate = '6/29/2018'
:
虽然我只需要列
YearNum
,
MonthNum
,
Qtr
,EarnedPremium
我可以用 SQL 来写,但是
有什么方法可以在 DAX 中实现吗?
.pbix 文件可在此处获得:
https://www.dropbox.com/s/pbj61vsb20qbhzm/LossTriangleTest.pbix?dl=0
更新!
亚历克西斯,非常感谢你。 DAX 可以用这些数字做些什么真是太神奇了。
出于某种原因,它总是给我赚取的保费总额略高于原始保费。
例如,PolicyNumber 'PACA1000101-00' 的总保费为 $10,568,但计算得出的已赚取为 $10,596。 2013 年 4 月 稍微多一点。
我认为需要针对最后一个细分 (EndRiskMonth) 实施一些额外的逻辑。
(来自 Power BI 的结果。抱歉,尚未排序)
来自 SQL 的结果:
如您所见,2013 年 4 月有 26 天。
这就是我在 SQL 中的做法,如果有帮助的话。 (在 SSMS 中可以是 运行)
DECLARE @PlazaInsuranceWPDataSet TABLE (
PolicyNumber varchar(50),
TransactionEffectiveDate datetime,
TransactionExpirationDate datetime,
WrittenPremium money
)
INSERT INTO @PlazaInsuranceWPDataSet values ('PACA1000101-00', '2012-04-27','2013-04-27',6630.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',1600.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',490.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',-77.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',1925.00 )
; WITH Earned_to_date AS (
SELECT Cast('2019-06-30' AS DATE) AS Earned_to_date
), policy_data AS (
SELECT
PolicyNumber
, Cast(TransactionEffectiveDate AS DATE) AS TransactionEffectiveDate
, Cast(TransactionExpirationDate AS DATE) AS TransactionExpirationDate
, WrittenPremium
FROM @PlazaInsuranceWPDataSet
)
, 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
PolicyNumber
, 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
, WrittenPremium
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 PolicyNumber,
StartRiskMonth,
EndRiskMonth,
YEAR(StartRiskMonth) as YearNum,
MONTH(StartRiskMonth) as MonthNum,
DATEPART(qq, StartRiskMonth) AS Qtr,
policy_days,
sum(WrittenPremium) as WrittenPremium,
DateDiff(day, StartRiskMonth, EndRiskMonth) AS DaysInMonth,
sum(WrittenPremium * DateDiff(day, StartRiskMonth, EndRiskMonth) / NULLIF(policy_days,0)) as EarnedPremium
FROM policy_dates
GROUP BY PolicyNumber, StartRiskMonth, EndRiskMonth
, DateDiff(day, StartRiskMonth, EndRiskMonth),policy_days
ORDER BY PolicyNumber, StartRiskMonth
更新!
亚历克西斯,
我在日历中修改了"EoMonth" table EOMONTH([Month], 0)+1
--added + 1
在交叉表中 "DaysInMonth", [EndRiskMonth] - [StartRiskMonth],
--起飞 1
以及赚取的保费
"EarnedPremium", [Premium] *
DIVIDE([EndRiskMonth] - [StartRiskMonth] , [End] - [Start])) --took off 1.
结果现在看起来像这样:
您应该可以使用某些 SUMMARIZE
、ADDCOLUMNS
和 SELECTCOLUMNS
函数来执行此操作。
首先,创建一个 'Calendar'
table 沿着这些行:
Calendar = SUMMARIZE(
ADDCOLUMNS(CALENDARAUTO(),
"Month", EOMONTH([Date], - 1) + 1),
[Month],
"EoMonth", EOMONTH([Month], 0))
然后您可以像这样将此 table 与您的 fact_Losses
table 交叉连接:
CrossTable =
VAR CrossTables =
CROSSJOIN(
SUMMARIZE(fact_Losses,
fact_Losses[PolicyNumber],
"Start", MIN(fact_Losses[PolicyEffectiveDate]),
"End", MAX(fact_Losses[PolicyExpirationDate]),
"Premium", SUM(fact_Losses[WrittenPremium])),
'Calendar')
VAR RiskPeriods =
ADDCOLUMNS(
FILTER(CrossTables,
'Calendar'[EoMonth] >= [Start] && 'Calendar'[Month] <= [End]),
"StartRiskMonth", IF([Start] > 'Calendar'[Month], [Start], 'Calendar'[Month]),
"EndRiskMonth", IF([End] < 'Calendar'[EoMonth], [End], 'Calendar'[EoMonth]))
RETURN SELECTCOLUMNS(RiskPeriods,
"PolicyNumber", fact_Losses[PolicyNumber],
"StartRiskMonth", [StartRiskMonth],
"EndRiskMonth", [EndRiskMonth],
"YearNum", YEAR('Calendar'[Month]),
"Qtr", ROUNDUP(MONTH('Calendar'[Month])/3, 0),
"MonthNum", MONTH('Calendar'[Month]),
"WrittenPremium", [Premium],
"DaysInMonth", [EndRiskMonth] - [StartRiskMonth] + 1,
"EarnedPremium", [Premium] *
DIVIDE([EndRiskMonth] - [StartRiskMonth] + 1, [End] - [Start]))
我有保费 TransactionEffectiveDate
和 TransactionExpirationDate
。
是否有任何方法可以在 DAX 中编写查询,该查询将获取每个保费金额并将其按这两个日期之间的月份进行细分。
@AsOfDate 参数将是政策停止收入的日期。
例如:
PolicyNumber WIC1000158-00
保费为 $82,913
和 TransactionEffectiveDate 1/5/2018
和TransactionExpirationDate 1/5/2019.
这给了我们总共 365 天的保单寿命。
让我们看看我们在 '06/29/2018' 之前赚了多少钱
因此 82,913 的保费应按 12 个月细分:
所以第一个保单月我们只有 27 天
所以 82,913/365 * 27 = 6,133.29 - 这就是第一个月的收入。
以此类推,直到@AsOfDate
。
结果应该像 @AsOfDate = '6/29/2018'
:
虽然我只需要列
YearNum
,
MonthNum
,
Qtr
,EarnedPremium
我可以用 SQL 来写,但是 有什么方法可以在 DAX 中实现吗?
.pbix 文件可在此处获得: https://www.dropbox.com/s/pbj61vsb20qbhzm/LossTriangleTest.pbix?dl=0
更新!
亚历克西斯,非常感谢你。 DAX 可以用这些数字做些什么真是太神奇了。
出于某种原因,它总是给我赚取的保费总额略高于原始保费。
例如,PolicyNumber 'PACA1000101-00' 的总保费为 $10,568,但计算得出的已赚取为 $10,596。 2013 年 4 月 稍微多一点。
我认为需要针对最后一个细分 (EndRiskMonth) 实施一些额外的逻辑。
(来自 Power BI 的结果。抱歉,尚未排序)
来自 SQL 的结果:
如您所见,2013 年 4 月有 26 天。
这就是我在 SQL 中的做法,如果有帮助的话。 (在 SSMS 中可以是 运行)
DECLARE @PlazaInsuranceWPDataSet TABLE (
PolicyNumber varchar(50),
TransactionEffectiveDate datetime,
TransactionExpirationDate datetime,
WrittenPremium money
)
INSERT INTO @PlazaInsuranceWPDataSet values ('PACA1000101-00', '2012-04-27','2013-04-27',6630.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',1600.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',490.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',-77.00 ),
('PACA1000101-00', '2012-04-27','2013-04-27',1925.00 )
; WITH Earned_to_date AS (
SELECT Cast('2019-06-30' AS DATE) AS Earned_to_date
), policy_data AS (
SELECT
PolicyNumber
, Cast(TransactionEffectiveDate AS DATE) AS TransactionEffectiveDate
, Cast(TransactionExpirationDate AS DATE) AS TransactionExpirationDate
, WrittenPremium
FROM @PlazaInsuranceWPDataSet
)
, 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
PolicyNumber
, 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
, WrittenPremium
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 PolicyNumber,
StartRiskMonth,
EndRiskMonth,
YEAR(StartRiskMonth) as YearNum,
MONTH(StartRiskMonth) as MonthNum,
DATEPART(qq, StartRiskMonth) AS Qtr,
policy_days,
sum(WrittenPremium) as WrittenPremium,
DateDiff(day, StartRiskMonth, EndRiskMonth) AS DaysInMonth,
sum(WrittenPremium * DateDiff(day, StartRiskMonth, EndRiskMonth) / NULLIF(policy_days,0)) as EarnedPremium
FROM policy_dates
GROUP BY PolicyNumber, StartRiskMonth, EndRiskMonth
, DateDiff(day, StartRiskMonth, EndRiskMonth),policy_days
ORDER BY PolicyNumber, StartRiskMonth
更新!
亚历克西斯,
我在日历中修改了"EoMonth" table EOMONTH([Month], 0)+1
--added + 1
在交叉表中 "DaysInMonth", [EndRiskMonth] - [StartRiskMonth],
--起飞 1
以及赚取的保费
"EarnedPremium", [Premium] *
DIVIDE([EndRiskMonth] - [StartRiskMonth] , [End] - [Start])) --took off 1.
结果现在看起来像这样:
您应该可以使用某些 SUMMARIZE
、ADDCOLUMNS
和 SELECTCOLUMNS
函数来执行此操作。
首先,创建一个 'Calendar'
table 沿着这些行:
Calendar = SUMMARIZE(
ADDCOLUMNS(CALENDARAUTO(),
"Month", EOMONTH([Date], - 1) + 1),
[Month],
"EoMonth", EOMONTH([Month], 0))
然后您可以像这样将此 table 与您的 fact_Losses
table 交叉连接:
CrossTable =
VAR CrossTables =
CROSSJOIN(
SUMMARIZE(fact_Losses,
fact_Losses[PolicyNumber],
"Start", MIN(fact_Losses[PolicyEffectiveDate]),
"End", MAX(fact_Losses[PolicyExpirationDate]),
"Premium", SUM(fact_Losses[WrittenPremium])),
'Calendar')
VAR RiskPeriods =
ADDCOLUMNS(
FILTER(CrossTables,
'Calendar'[EoMonth] >= [Start] && 'Calendar'[Month] <= [End]),
"StartRiskMonth", IF([Start] > 'Calendar'[Month], [Start], 'Calendar'[Month]),
"EndRiskMonth", IF([End] < 'Calendar'[EoMonth], [End], 'Calendar'[EoMonth]))
RETURN SELECTCOLUMNS(RiskPeriods,
"PolicyNumber", fact_Losses[PolicyNumber],
"StartRiskMonth", [StartRiskMonth],
"EndRiskMonth", [EndRiskMonth],
"YearNum", YEAR('Calendar'[Month]),
"Qtr", ROUNDUP(MONTH('Calendar'[Month])/3, 0),
"MonthNum", MONTH('Calendar'[Month]),
"WrittenPremium", [Premium],
"DaysInMonth", [EndRiskMonth] - [StartRiskMonth] + 1,
"EarnedPremium", [Premium] *
DIVIDE([EndRiskMonth] - [StartRiskMonth] + 1, [End] - [Start]))