PowerBI之DAX神功:第1卷第20回 循環(huán)依賴什么鬼?
一、循環(huán)依賴之時間旅行者
循環(huán)依賴是鬼,它活著的時候叫循環(huán)引用。
《大話西游大圣娶妻》紫霞仙子說了幾句牛魔王聽不懂的話:),牛魔王對青霞說:“你妹妹瘋了,說了一晚上鬼話!”
大家要知道,循環(huán)依賴和循環(huán)引用,是一回事,只是活著和死了叫法不一樣

【新建列】兒子 = 'Sheet2'[父]+'Sheet2'[母]?
【新建列】孫子 = 'Sheet2'[兒子]+'Sheet2'[兒媳]?
我再修改【兒子】列時,就提示檢測到循環(huán)依賴
兒子 = 'Sheet2'[父]+'Sheet2'[孫子]

這樣造成的循環(huán)依賴的原因,大家都清楚:
兒子的出生與孫子無關(guān),沒有兒子哪來的孫子?
孫子列是依賴兒子列生成的,你再又讓兒子列依賴孫子列生成,是不行的。
二、第二次使用Calculate新建列造成的循環(huán)引用

【新建列】銷售金額 = sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[售價])

新建列(銷售金額)是行上下文沒有篩選功能,這個表中任何列都不能篩選它

【新建列】銷售金額 = calculate(sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[售價]))

當套上Calculate之后,所有字段都可以篩選了

當我寫第2個新建列時
銷售成本 = sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[進價])

這樣寫,哪個列都不能篩選,沒問題。但是,我給它也套上一個Calculate時,出問題了:
銷售成本 = CALCULATE(sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[進價]))

《The Definitive Guide to DAX》中的解釋非常專業(yè),也許你能看懂,但是你不可能每次都將他展開找原因。
DAX神功解釋:得語文者得天下,得閱讀者得語文

這句話已經(jīng)說得很清楚了,銷售成本這列,不能被銷售金額這個列篩選
你寫成下面這樣,取消銷售金額這個列的篩選就可以了。
銷售成本 = CALCULATE(sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[進價]),all(Sheet3[銷售金額]))

sumx本來是行上下文,你通過calculate強行轉(zhuǎn)化為篩選上下文
被強行轉(zhuǎn)化的這兩列分別是:銷售金額和銷售成本
銷售金額通過前4列篩選:商品、銷量、售價、進價

銷售成本 = CALCULATE(sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[進價]))
這樣寫出來的銷售成本,原則上按前5列篩選:商品、銷量、售價、進價、銷售金額
銷售金額依賴前4列篩選,它就不能再去篩選銷售成本,所以要取消銷售金額的篩選

首先,篩選器不能重復
其次,篩選器不能隔山打牛
所以,這樣寫也是錯的,因為隔山打牛
銷售成本 = CALCULATE(sumx('Sheet3','Sheet3'[銷量]*'Sheet3'[進價]),ALL('Sheet3'[商品],Sheet3[銷量],Sheet3[售價],Sheet3[進價]))

上面的公式,相當于取消了前4列的篩選,使用銷售金額篩選,這樣隔山打牛是不行的。
三、多表循環(huán)依賴的處理方法


現(xiàn)在這兩張表無法建立關(guān)系,沒有主鍵和外鍵
【度量值】總分1 = SUM('成績表'[分數(shù)])
【新建列】等級1 = SWITCH(TRUE(),[總分1]>90,"S",[總分1]>60,"A","B")

【新建列】新列 = [等級1]&"-MG"

怎么解決?因為現(xiàn)在只有一張表,按照單張表處理方法,修改度量值:
【度量值】總分1 = CALCULATE(SUM('成績表'[分數(shù)]),ALL('成績表'[新列]))

現(xiàn)在我們將【總分1】度量值恢復,并且刪除【新列】
【度量值】總分1 = SUM('成績表'[分數(shù)])

兩表連線會出現(xiàn)循環(huán)引用:

DAX神功完整解釋:如果使用成績表[等級1]與評價表[等級]連線,由于【總分1】這個度量值的上下文作用,成績表[等級1]就會與評價表[等級]產(chǎn)生依賴關(guān)系,而評價表[等級]又通過成績表和評價表直接的關(guān)聯(lián)關(guān)系與成績表[等級1]產(chǎn)生依賴,這就形成了一個循環(huán)依賴關(guān)系,所以這兩個表不能使用等級字段創(chuàng)建關(guān)系。
我擔心你看不懂這段話,所以我畫個圖:

當一端表和多端表建立連線關(guān)系后,其實表格是這樣的:

就相當于是,1端表中的所有列都Vlookup到了多端表中去了。
現(xiàn)在修改度量值,你只寫all(等級1)是不行的,因為連線后,評價表字段也牽連進來了,
【度量值】總分1 = CALCULATE(SUM('成績表'[分數(shù)]),ALL('成績表'[等級1]))
可是兩個表沒建立關(guān)系之前,你的度量值里無法引用其它表中的列,這時ALLexcept就有了它無法替代的作用

總分1 = CALCULATE(SUM('成績表'[分數(shù)]),ALLEXCEPT('成績表','成績表'[學號],'成績表'[科目],'成績表'[分數(shù)]))
只允許學號,科目,分數(shù)列篩選,取消其它所有列的篩選。
有些人會說,不對呀,寫成這樣也可以
總分1 = CALCULATE(SUM('成績表'[分數(shù)]),ALLEXCEPT('成績表','成績表'[學號]))
寫成什么樣是根據(jù)你的業(yè)務需求決定的,但是,循環(huán)依賴這個鬼,你必須保證? ? 成績表中的等級1和評價表里所有列在【總分1】度量值中取消篩選
關(guān)于其它列是否篩選,由你自己決定。
四、九叔重現(xiàn),避開鬼打墻,多表循環(huán)依賴的處理方法:


這次看每個人數(shù)學和語文的總分數(shù)+花名冊中的加分后得到的每個人總分
大于等于180是S, 大于等于120是A,否則是B

我們在《DAX神功》第1卷第14回 講過,寫法不止下面一種
[新建列]
總分 =?
? ? var x = '成績表'[學號]
? ? return
? ? ? ? sumx(FILTER('成績表','成績表'[學號]=x),'成績表'[分數(shù)]+RELATED('花名冊'[加分]))?

新建列浪費內(nèi)存,我們一般會使用度量值方式。
[度量值]
總分 =?
? ? var x = SELECTEDVALUE('成績表'[學號])
? ? return
? ? ? ? sumx(FILTER(all('成績表'),'成績表'[學號]=x),'成績表'[分數(shù)]+RELATED('花名冊'[加分]))?

[新建列]
等級 = SWITCH(TRUE(),[總分]>=180,"S",[總分]>=120,"A","B")

現(xiàn)在評價表與成績表通過等級連線就不會出現(xiàn)循環(huán)依賴的問題了,當前行概念就是九叔,避開鬼打墻。
五、度量值出現(xiàn)循環(huán)引用的概率低


表格白底黑字是網(wǎng)友留言中敘述的原始表,綠底黑字是我在Excel中計算的結(jié)果
將白底黑字表格放到PowerBI中,寫如下度量值:
本月平均單價 = DIVIDE(sumx('Sheet4','Sheet4'[上月末金額]+'Sheet4'[本月入庫金額]),sumx('Sheet4','Sheet4'[月初數(shù)量]+'Sheet4'[本月入庫數(shù)量]))
本月出庫金額 = sum(Sheet4[出庫數(shù)量])*[本月平均單價]
下月初金額 = SUM(Sheet4[上月末金額])+sum(Sheet4[本月入庫金額])-[本月出庫金額]?

完全正常沒有問題。度量值是不易出現(xiàn)循環(huán)引用的,也不是絕對,比如講時間智能日期函數(shù)時就會遇到。
建議:
度量值1和5完全沒有必要寫,心里明白就可以了
打個比方,公司集體會議,無論什么職務,開會點名都答“到”!
我叫孫興華,是公司的副總裁,同時也是總經(jīng)理。
你喊我孫興華,我答“到”!就可以了!叫我一次就可以了,不能因為我有兩個職務,你就喊我兩次。
如果你喊副總裁,很有可能是總裁答“到”!總裁有可能姓付。
不做無意義的重復勞動。
關(guān)于度量值中的循環(huán)引用,我們后期課程中還會涉及,敬請期待。
