使 DAX 代码更高效 - 计算重叠日期范围内的唯一开始日期
Making DAX code more efficient - counting unique Start dates in overlapping date ranges
我有一个 table 超过 25 年的每个客户购买的每件产品。 table 包含客户编号、产品、开始日期和结束日期。
产品可以由客户拥有任何时间(1 天到 100 年)。当客户拥有我们的产品时,客户是活跃的。如果客户终止所有产品,他们将不再是客户。我想计算每年新客户的开始。问题是,一些客户结束所有产品然后在几年后再次开始购买产品(但客户总是保留同一个客户#) - 如果客户离开然后在一年后重新加入我想将客户视为新客户。
我已经创建了 DAX 代码来执行此操作,它可以在一个小文件上完美运行,但是该代码占用了太多资源,因此我无法在我的数据(大约 200,000 条记录)上使用它。我知道我的代码非常低效,可能会被清理……但我不确定如何清理。或者,如果我能弄清楚如何在 PowerQuery 中制作这些列,也许那会奏效
这是我的做法。
1) 将四个计算列添加到我的 table:
VeryFirstStart = Calculate(
Min('Products'[StartDate]),
ALLEXCEPT(Products,Products[ClientNumber]))=Products[StartDate]
这会标记包含任何客户的第一个开始日期的记录
MaxEndDateofEarlierDates = Calculate(
Max('Products'[EndDate]),
Filter(
Filter(ALLEXCEPT(Products, Products[ClientNumber]), Products[EndDate]),
Products[StartDate] < EARLIER(Products[StartDate])))
这一步让我的 PowerBI 崩溃了——这显示了任何新产品的购买日期,其中新的开始日期发生在结束日期之后
Second+Start = And(
Products[MaxEndDateofEarlierDates]<>BLANK(),
Products[MaxEndDateofEarlierDates]<Products[StartDate])
这标记了我们要将新开始日期计为新客户的记录
NewStart = OR(Products[Second+Start],Products[VeryFirstStart])
**这会标记任何新客户的开始日期,无论它是第一个还是后续*
最后我添加了这个措施:
!MemberNewStarts = CALCULATE(
DISTINCTCOUNT(Products[ClientNumber]),
FILTER(
'Products',
('Products'[StartDate] <= LASTDATE('DIMDate'[Date]) &&
'Products'[StartDate]>= FIRSTDATE('DIMDate'[Date]) &&
Products[NewStart]=TRUE())))
有没有人对如何用更少的资源实现这一目标有任何建议?
谢谢
这里有一些数据可以尝试
MemberNumber Product StartDate EndDate Note (not in real data)
1 A 02/02/2003 02/02/2004
1 C 02/02/2009 02/02/2010
2 A 02/02/2001 02/02/2002
2 C 02/02/2001 02/02/2002
2 B 02/02/2005 02/02/2010
3 C 02/02/2002 02/02/2005
3 B 02/02/2002 02/02/2005
3 A 02/02/2003 02/02/2008
4 B 02/02/2002 02/02/2003
4 C 02/02/2003 02/02/2006
5 B 02/02/2003 02/02/2007
5 C 02/02/2005 02/02/2010
5 A 02/02/2005 02/02/2007
6 A 02/02/2001 02/02/2006
6 C 02/02/2003 02/02/2007
7 B 02/02/2001 02/02/2004
7 A 02/02/2001 02/02/2005
7 C 02/02/2005 02/02/2006
8 B 02/02/2002 02/02/2006
8 A 02/02/2004 02/02/2009
注意成员 1 在 2009 年作为新客户开始,因为所有以前的产品都在 2004 年结束,成员 2 在 2005 年作为新客户开始,因为所有以前的产品都在 2002 年结束
期望的结果是:
Start Year 2001 2002 2003 2004 2005 2006 2007 2008
New Clients 3 3 2 0 1 0 0 0
这是尝试解决它的一种方法。让我知道这是否比你的更有效:
第一个新专栏:
PreviousHighestFinish:=
Calculate(
Max(Products[EndDate]),
ALLEXCEPT(Products,Products[ClientNumber]),
Products[StartDate] < Earlier(Products[StartDate]
)
这将为您提供客户编号匹配且开始日期早于当前开始日期的最晚结束日期。如果没有更早的开始日期,它 returns 空白。
第二个新专栏:
NewClientProduct:=
if(Products[StartDate]>=Products[PreviousHighestFinish],1,0)
这将为您以前未见过客户(并且前一列显示为空白)或以前见过客户但没有当前产品的每一行提供 1。
此措施的问题在于,如果您有一个客户在同一天开始使用多个产品,他们将显示为多个新客户。
解决这个问题的方法是计算每个客户-日期组合的实例
第 3 个新专栏:
ClientDateCount:=
CALCULATE(
COUNTROWS(Products),
ALLEXCEPT(Products,Products[ClientNumber],Products[StartDate])
)
这基本上给出了 table 中这一行的客户在该日期开始使用产品的次数。
现在将第二个新列除以这一列
第 4 个新专栏:
NewClients:=
DIVIDE(Products[NewClientProduct],Products[ClientDateCount])
瞧:
我有一个 table 超过 25 年的每个客户购买的每件产品。 table 包含客户编号、产品、开始日期和结束日期。 产品可以由客户拥有任何时间(1 天到 100 年)。当客户拥有我们的产品时,客户是活跃的。如果客户终止所有产品,他们将不再是客户。我想计算每年新客户的开始。问题是,一些客户结束所有产品然后在几年后再次开始购买产品(但客户总是保留同一个客户#) - 如果客户离开然后在一年后重新加入我想将客户视为新客户。
我已经创建了 DAX 代码来执行此操作,它可以在一个小文件上完美运行,但是该代码占用了太多资源,因此我无法在我的数据(大约 200,000 条记录)上使用它。我知道我的代码非常低效,可能会被清理……但我不确定如何清理。或者,如果我能弄清楚如何在 PowerQuery 中制作这些列,也许那会奏效
这是我的做法。
1) 将四个计算列添加到我的 table:
VeryFirstStart = Calculate(
Min('Products'[StartDate]),
ALLEXCEPT(Products,Products[ClientNumber]))=Products[StartDate]
这会标记包含任何客户的第一个开始日期的记录
MaxEndDateofEarlierDates = Calculate(
Max('Products'[EndDate]),
Filter(
Filter(ALLEXCEPT(Products, Products[ClientNumber]), Products[EndDate]),
Products[StartDate] < EARLIER(Products[StartDate])))
这一步让我的 PowerBI 崩溃了——这显示了任何新产品的购买日期,其中新的开始日期发生在结束日期之后
Second+Start = And(
Products[MaxEndDateofEarlierDates]<>BLANK(),
Products[MaxEndDateofEarlierDates]<Products[StartDate])
这标记了我们要将新开始日期计为新客户的记录
NewStart = OR(Products[Second+Start],Products[VeryFirstStart])
**这会标记任何新客户的开始日期,无论它是第一个还是后续*
最后我添加了这个措施:
!MemberNewStarts = CALCULATE(
DISTINCTCOUNT(Products[ClientNumber]),
FILTER(
'Products',
('Products'[StartDate] <= LASTDATE('DIMDate'[Date]) &&
'Products'[StartDate]>= FIRSTDATE('DIMDate'[Date]) &&
Products[NewStart]=TRUE())))
有没有人对如何用更少的资源实现这一目标有任何建议?
谢谢
这里有一些数据可以尝试
MemberNumber Product StartDate EndDate Note (not in real data)
1 A 02/02/2003 02/02/2004
1 C 02/02/2009 02/02/2010
2 A 02/02/2001 02/02/2002
2 C 02/02/2001 02/02/2002
2 B 02/02/2005 02/02/2010
3 C 02/02/2002 02/02/2005
3 B 02/02/2002 02/02/2005
3 A 02/02/2003 02/02/2008
4 B 02/02/2002 02/02/2003
4 C 02/02/2003 02/02/2006
5 B 02/02/2003 02/02/2007
5 C 02/02/2005 02/02/2010
5 A 02/02/2005 02/02/2007
6 A 02/02/2001 02/02/2006
6 C 02/02/2003 02/02/2007
7 B 02/02/2001 02/02/2004
7 A 02/02/2001 02/02/2005
7 C 02/02/2005 02/02/2006
8 B 02/02/2002 02/02/2006
8 A 02/02/2004 02/02/2009
注意成员 1 在 2009 年作为新客户开始,因为所有以前的产品都在 2004 年结束,成员 2 在 2005 年作为新客户开始,因为所有以前的产品都在 2002 年结束
期望的结果是:
Start Year 2001 2002 2003 2004 2005 2006 2007 2008
New Clients 3 3 2 0 1 0 0 0
这是尝试解决它的一种方法。让我知道这是否比你的更有效:
第一个新专栏:
PreviousHighestFinish:=
Calculate(
Max(Products[EndDate]),
ALLEXCEPT(Products,Products[ClientNumber]),
Products[StartDate] < Earlier(Products[StartDate]
)
这将为您提供客户编号匹配且开始日期早于当前开始日期的最晚结束日期。如果没有更早的开始日期,它 returns 空白。
第二个新专栏:
NewClientProduct:=
if(Products[StartDate]>=Products[PreviousHighestFinish],1,0)
这将为您以前未见过客户(并且前一列显示为空白)或以前见过客户但没有当前产品的每一行提供 1。
此措施的问题在于,如果您有一个客户在同一天开始使用多个产品,他们将显示为多个新客户。
解决这个问题的方法是计算每个客户-日期组合的实例
第 3 个新专栏:
ClientDateCount:=
CALCULATE(
COUNTROWS(Products),
ALLEXCEPT(Products,Products[ClientNumber],Products[StartDate])
)
这基本上给出了 table 中这一行的客户在该日期开始使用产品的次数。
现在将第二个新列除以这一列
第 4 个新专栏:
NewClients:=
DIVIDE(Products[NewClientProduct],Products[ClientDateCount])
瞧: