第一章
DataModel的概念
通過各種關(guān)系連接起來的表群挡逼。其中的關(guān)鍵點在于關(guān)系和表群部念。
-
為什么要用表群
如果可以只適用一個表就不行么穴翩?這樣的話就不用考慮各種表之間的關(guān)系邀窃,也更利于數(shù)據(jù)的計算和分析荸哟。
把所有的字段放在一個表,肯定是可以的瞬捕,但是顯而易見的是這樣會增加表的體積鞍历。假設(shè)原來的主數(shù)據(jù)只有10行,交易數(shù)據(jù)有1000行肪虎,如果強行合并劣砍,肯定是需要把主數(shù)據(jù)的各個字段擴展到1000行。另外扇救,如果是兩個交易的表的情況下呢刑枝,比如銷售類的數(shù)據(jù)和出庫類的數(shù)據(jù)香嗓,這樣強行整合為一個大表的話,肯定會有很多無用的數(shù)據(jù)重復(fù)多次∽俺現(xiàn)今靠娱,內(nèi)存雖然便宜,但是還沒有便宜到可以隨意浪費的地步掠兄。
所以不嚴(yán)謹(jǐn)?shù)恼f數(shù)據(jù)倉庫發(fā)展到現(xiàn)在像云,為了跟快的反饋查詢結(jié)果,一直在重復(fù)的就是選擇時間換空間還是選擇空間換時間蚂夕。 -
關(guān)系
當(dāng)決定通過關(guān)系把所有的表鏈接起來的話苫费,各個表之間的關(guān)系就會變得微妙起來。表的連接方式無非就是1:1或1:N或M:N双抽。1:1的情況下表的聯(lián)動是最簡單的是對等的百框,如果是1:N或者M:N的情況下就需要考慮一個問題就是兩個表之間是如何聯(lián)動的,即如何追溯和回溯牍汹?如從一個表如何過濾另外一張表的數(shù)據(jù)铐维,如果使用兩個表的字段計算一個新的字段。這是最需要關(guān)注的一點慎菲。
單向關(guān)系和雙向關(guān)系
單向和雙向的關(guān)系嫁蛇,單向雙向影響的是維度表之間的跨表的計算,所有的維度表是與事實表進行關(guān)聯(lián)露该,那么維度表就通過事實表進行間接的關(guān)聯(lián)睬棚,這個時候單向和雙向在統(tǒng)計這種間接關(guān)聯(lián)的維度表中的數(shù)據(jù)的時候,會發(fā)生差異解幼。
下圖中抑党,參與計算的除了事實表中的數(shù)量,還有維度表中的產(chǎn)品(進行了count計算)撵摆。Calendar Year來源于Date維度表底靠,Product來源于Product維度表,分別與Sales表進行1:N的鏈接特铝。
對于1:N的關(guān)系暑中,書中說到過濾總是從1到N的方向進行過濾,這里的過濾可以理解為切片鲫剿,比如表中添加了Year這個維度鳄逾,相當(dāng)于這個表使用Year對數(shù)據(jù)進行了切片,那么N方向的事實表的數(shù)據(jù)灵莲,就會按照這個切片進行分類匯總雕凹。如圖中的數(shù)量字段按照年進行匯總。
跨表過濾(cross filter)- 間接過濾,單雙向的差別在這里會出現(xiàn)差異请琳,如下圖中Product Name的計數(shù)是不一樣的。原因在于單向的情況下赠幕,過濾(切片)總是從1到N的俄精,這種情況下,年的切片其實是沒有辦法傳遞到Product維度表中的榕堰,即年的切片是對Product中字段的計算是不起作用的竖慧,因此Product Name的計數(shù)是對整個Product表中的Priduct Name進行計數(shù)匯總,然后顯示在每一年下邊逆屡。因此看到的是年由原來的三個變成了七個圾旨,2517是Product為維度表的product name的計數(shù)總和,重復(fù)的顯示在了每一個年份中魏蔗。
現(xiàn)在去掉這個Product Name的計數(shù)砍的,同時添加Product中一個屬性到這個表中,結(jié)果就相當(dāng)于Date維度表和Product維度表同時對Sales事實表進行過濾(切片)莺治。這種情況下其實單雙向沒任何區(qū)別廓鞠,因為不涉及到過濾的傳遞,而只是同時過濾谣旁。
Other Point
- In DAX, relationships are part of the model, and they are all LEFT OUTER JOINs.
對于這句話床佳,有兩個疑問,第一以什么為主表的左連榄审?怎么確定這個主表呢砌们?第二,如果兩個以上的事實表的話搁进,是如何處理的浪感?比如庫存和銷售。 - DAX is a function language. In DAX, every expression is a function call. Function parameters can be other function calls.
對應(yīng)于函數(shù)式編程?
Tips
DAX中沒有l(wèi)oop / Do循環(huán)
SUM(表達式) 對行計算
SUMX(表饼问,表達式) 按行循環(huán)
第二章
注釋:單行 -- // 多行 /* ... */
計算列和指標(biāo)
計算列:依附于某個表篮撑,作為表的一個列,因此于此表有著同樣的行匆瓜,也就是說計算列是按照每一行的數(shù)據(jù)進行計算并存儲在內(nèi)存中的赢笨,是占用了空間的,可以認(rèn)為是表的一部分驮吱。當(dāng)數(shù)據(jù)抽取的時候發(fā)生的茧妒,而非在查詢的時候才計算出來,因此占用的是抽取時間而非查詢時間左冬。
當(dāng)創(chuàng)建計算列的時候桐筏,這個列的維度或者說顆粒度已經(jīng)確定了,這里的每行就是最細的顆粒度拇砰。
指標(biāo):首先是不是依附于某一個具體的表梅忌,可以認(rèn)為是基于整個模型的狰腌,因此他是沒有具體的行的概念,也不是提前計算出來的牧氮。而是當(dāng)你使用的時候根據(jù)當(dāng)前可視化區(qū)域的切片/維度進行臨時計算出來的結(jié)果琼腔。
指標(biāo)創(chuàng)建的時候,并沒有制定維度或者說顆粒度踱葛,他的結(jié)果或者他的顆粒度是根據(jù)報表中顯示的維度而確定的丹莲,從而基于此顆粒度進行最終結(jié)果的計算。
-- 這樣的理解貌似有點問題尸诽。
首先指標(biāo)的創(chuàng)建也是選中某一個表然后進行創(chuàng)建的甥材,所以應(yīng)該還是依附于某一個表的。在創(chuàng)建指標(biāo)的時候性含,首選是要選擇匯總的類型洲赵,比如選擇SUM然后才能跳出來字段以供選擇,否則是沒有辦法創(chuàng)建指標(biāo)的商蕴。
即先定義指標(biāo)的匯總方式板鬓,然后決定按照什么樣的顆粒度進行匯總,而計算列的話是先定義顆粒度(或者說默認(rèn)顆粒度就是所在表的行級別)究恤,然后再使用的時候再定義匯總類型俭令。
計算列和指標(biāo)的圖標(biāo)是完全不一樣的。
也可以簡單的從以下角度理解兩者的區(qū)別部宿,計算列就是相當(dāng)于從數(shù)據(jù)源選擇數(shù)據(jù)的時候抄腔,新增的一列。即select calculate* as B from ***理张。進入到PBI的之后赫蛇,就完全可以看作是一個表的列,這個列與其他的列沒有什么本質(zhì)的區(qū)別雾叭。而指標(biāo)悟耘,就相當(dāng)于一個管道/漏斗,他只會把你給的東西匯總起來织狐,當(dāng)你把某個字段拉到報表中顯示的時候暂幼,這個漏斗就根據(jù)這個字段把所有的數(shù)據(jù)分別匯總并輸送到不同的目的地。
計算列就相當(dāng)于一個括號移迫,
當(dāng)計算只涉及到加減的時候旺嬉,這個括號其實是沒有什么作用的;
當(dāng)計算開始涉及到乘除的時候厨埋,這個括號的作用就開始顯現(xiàn)出來邪媳,因為加減乘除會根據(jù)這個括號調(diào)整計算的優(yōu)先級。
比如:毛利率
SUM(Margin/Sales)
SUM(Margin)/SUM(Sales)
簡而言之:
計算列:無需定義匯總類型,顆粒度為行級別雨效,表更新的時候直接創(chuàng)建迅涮,占用內(nèi)存空間,不受用戶過濾的影響徽龟,相當(dāng)于固定計算出一列值并存儲在表中叮姑;
指標(biāo):先定義匯總類型,顆粒度按照使用圖表的顆粒度顿肺,使用的時候臨時計算戏溺,不存儲渣蜗,受用戶過濾器的影響屠尊,相當(dāng)于一個動態(tài)的函數(shù)計算值,隨選擇變動耕拷;
應(yīng)該跟tableau中的LOD比較一下讼昆。
如何選擇,兩個應(yīng)該基本都可以實現(xiàn)相同的功能骚烧,因此由時間換空間還是空間換時間決定浸赫;官方推薦用指標(biāo)。 :-)
變量
用Var定義赃绊,用Return返回計算的值。
變量全部都是本地變量,沒有全局變量择懂,即變量值在定義的那個地方(定義時候的那個公示欄中)被使用耗帕,不能跨指標(biāo)調(diào)用。 -- 那就把本地變量變成指標(biāo)忠售,不就成為全局變量了么传惠。
同時變量在被用到的時候才會被檢驗同時被計算,只需要計算一次可以在多個地方使用稻扬。
BLANK () = 0 -- Always returns TRUE
BLANK () = "" -- Always returns TRUE
BLANK () = 0 = FALSE
BLANK () + BLANK () = BLANK ()
BLANK () / BLANK () = BLANK ()
10 * BLANK () = BLANK ()
BLANK () / 3 = BLANK ()
4 / BLANK () = Infinity
0 / BLANK () = NaN
When using variables, errors must be checked at the time of variable definition rather than where we use them. DAX engine cannot use optimized paths in its code when errors happen.
SUM, AVERAGE, MIN, MAX... -- 一步操作卦方,列行為,對某列進行操作泰佳,只接受值盼砍,不接受表達式;所以復(fù)雜操作必須引入計算列逝她;
需要驗證衬廷,邏輯上來講匯總細化到操作層面也是行的行為,最后在進行匯總操作汽绢,只是這個行行為是直接由函數(shù)定死的吗跋,無法進行雙重操作,因為必須傳入的是值而非表達式。 Aggregators are just a syntax-sugared version of iterators跌宛。
SUMX, AVERAGEX, MINX, MAXX...--兩步操作酗宋,行行為,之后按照匯總類型進行匯總疆拘,接受值和表達式蜕猫;復(fù)雜計算可以直接使用多重表達式嵌套。
COUNTA, AVERAGEA, MINA, MAXA...these functions are useful only for columns containing Boolean values,Text columns are always considered 0哎迄。
the functions ISNUMBER, ISTEXT, and ISNONTEXT always return TRUE or FALSE depending on the data type of the column and on the empty condition of each cell.根據(jù)定義的列的類型回右,所以這幾個函數(shù)沒什么用。除非先用Value進行轉(zhuǎn)換漱挚,然后再做判定翔烁。
Related返回一個值,RelatedTable返回多個值組成一個表旨涝。
第三章
如果定義了多個表變量蹬屹,其數(shù)據(jù)分別來源于不同的表,那么這個時候使用的連接還是原先定義的鏈接白华?
兩個表的字段相乘慨默?
如果新建一個calculatedTable,那么會復(fù)制源表的所有內(nèi)容弧腥,如果原表有計算列厦取,那么復(fù)制過來的就變成了值列了,即看不到原來的計算公式管搪。
所有帶All的函數(shù)虾攻,無視所有的切片/過濾器
All可以得到輸入字段或者表的最細維度的值清單;
Value可以得到輸入列或者表的值清單抛蚤,但是多了一個空值(當(dāng)事實表中的維度值不存在于維度表的時候台谢,才會多一個空值去存儲所有不存在于維度表的值,如果都存在的話岁经,不會多一個空值)朋沮;
Distinct可以得到輸入列或者表的值清單,不包含空值缀壤;
SELECTEDVALUE ('Product'[Brand], "Multiple brands" )
CONCATENATEX (VALUES ( 'Product'[Brand] ),'Product'[Brand],", ")
第四章
The filter context filters; the row context iterates.
This means that the row context does not filter, and the filter context does not iterate.
第四章最重要的兩句話樊拓。
第五章
理解CALCULATE和CALCULATETABLE
CALCULATE中引用的過濾條件,可以直接使用相關(guān)聯(lián)表中的字段塘慕,不必要使用related去獲取相對應(yīng)的關(guān)系筋夏,也就是說,他只是起了一個過濾的作用图呢,并且這個過濾相當(dāng)于報表層面的過濾条篷,其中間的連接關(guān)系使用已經(jīng)定義好的對應(yīng)關(guān)系骗随。同時可以理解calculate不參與行計算,因此不需要根據(jù)每一行的內(nèi)容去獲取相關(guān)維度表中的內(nèi)容以進行判斷赴叹,只是起了一個過濾器的作用鸿染。
Before evaluating the expression, CALCULATE computes the filter arguments and uses them to manipulate the filter context。
即先過濾在計算乞巧,相當(dāng)于在后邊條件下的表中進行前邊的計算涨椒。
同時,calculate中的過濾器會覆蓋其他地方的過濾器绽媒,并且有一種ALL的感覺在里邊蚕冬。
關(guān)鍵點是,calcualte只覆蓋前一層的過濾是辕,只追溯一層囤热。
或者應(yīng)該理解為赢乓,calculate中用到的過濾取的維度都會被覆蓋忧侧。但不會影響到未在Calculate中使用到的維度的過濾器石窑。
看完這些,然后就輪到KEEPFILTERS出場拯救世界了蚓炬。
context transition
Sum Num Of Sales := SUMX ( Sales, COUNTROWS (Sales ) ),需要好好的理解下這個指標(biāo)最終給出的結(jié)果是什么松逊。
這里說的重點是如果Calcualte函數(shù)第二個參數(shù)如果是空的,那么會默認(rèn)在計算所依存的那個表中添加一個默認(rèn)的過濾器肯夏,然后再遍歷每行進行計算经宏。如下圖中M_Qty與Qty的不同之處。如果依存表中不存在兩行一模一樣的數(shù)據(jù)的話驯击,那么結(jié)果如上圖烁兰,與平常的計算是一致的,因為過濾器每次過濾都是一行數(shù)據(jù)徊都。
Sales Amount := SUMX( Sales, CALCULATE( SUM( Sales[Quantity] ) ) )
簡單理解的話可以理解為loop中套select沪斟;
loop sales condition X
select prod sum(qty)
from sales
where Condition X
endloop
在什么地方做什么事情
開始一層一層分析,假設(shè)這里的Sales表就是上圖中5行的那個Prod,Qty表暇矫;
- SUMX的邏輯是遍歷第一個參數(shù)的每一行主之,總共遍歷5次;在什么地方李根,
遍歷Sales的每一行槽奕,首先取第一行;Prod=A,Qty=10房轿;
- 第二個參數(shù)開始做計算粤攒;做什么事情
Calculate(SUM(Quantity))
2.0 Calculate的計算順序是反過來的所森,從后向前,所以第一步是過濾數(shù)據(jù)夯接,這里沒有傳入?yún)?shù)必峰,那么就相當(dāng)于先把外層的表復(fù)制過來,然后每一列都添加上過濾器钻蹬,也可以理解為把所有列Combine起來作為一個過濾字段吼蚁。
2.1 開始取第一個合并的key,然后執(zhí)行過濾问欠,過濾條件就是外側(cè)的那個Prod=A,Qty=5肝匆,這里可以過濾出來兩行;在什么地方顺献;
2.2 回到第一個參數(shù)進行計算旗国,這里就是SUM計算了,第一步獲得了兩行Prod=A,Qty=10注整,匯總起來就是20能曾,即Prod=A,Qty=20;做什么事情肿轨。
結(jié)束寿冕,跳出
執(zhí)行第二行的,同樣得到的也是Prod=A,Qty=20椒袍;
這兩行的結(jié)果匯總起來就變成了Prod=A,Qty=40驼唱。
相當(dāng)于下邊這樣
總結(jié)
- Context transition is expensive.
這里理解的expense不是loop套select的那種每次開關(guān)數(shù)據(jù)庫連接的expense,而是兩個循環(huán)互相嵌套的問題驹暑,即loop中套loop的那種內(nèi)存開銷玫恳,相當(dāng)于要做兩個表的行數(shù)相乘次的操作,所以會比較耗費內(nèi)存和時間优俘。 - Context transition does not only filter one row.
- Context transition is invoked whenever there is a row context.
意思就是loop中套的是一個select京办,這個select的結(jié)果可能是一條記錄,但絕對不會一直是一條記錄帆焕; - Context transition uses columns that are not present in the formula.
如果默認(rèn)過濾參數(shù)惭婿,那么所有的列合并起來會作為一個過濾的條件; - Context transition creates a filter context out of a row context.
- Context transition transforms all the row contexts.
- Context transition invalidates the row contexts.
這里說的意思應(yīng)該是select是from那個表视搏,而不是loop傳進來的那一條記錄审孽;
是不是可以說:
calculate(var) 等于 measure, measure是天然帶著calculate的var浑娜,var是天然去掉calculate的measure佑力,帶不帶calculate意味著是否進行語境傳遞?
計算列的話就是就是一個語境筋遭,但是是否使用這個語境要看使用什么樣的匯總方式打颤,是兩列相乘暴拄,還是sum(),或是sumx();
第六章
Var...Return编饺;
變量一經(jīng)計算乖篷,結(jié)果便不能夠在更改,哪怕對其重新計算重新調(diào)整過濾范圍透且;這句話說的有點問題撕蔼,變量什么時候計算呢?變量是包含在計算指標(biāo)中的秽誊,那么計算指標(biāo)在什么時候用呢鲸沮?用的時候是什么樣的context呢?如果計算指標(biāo)被用在兩個不同context的地方锅论,那么這個變量的值是一樣的么讼溺?
變量是定義的時候做校驗;
表變量代表的是原表的一個子集最易,所以使用字段的時候還是需要引用原表的字段怒坯,而非引用表變量的字段。
第七章
DAX邏輯基礎(chǔ)
row context / filter context / context transaction
報表層面的匯總藻懒,同一context下的內(nèi)容直接計算就結(jié)束了剔猿,不同context下的內(nèi)容的交叉計算是重點所在。
循環(huán)套循環(huán)一般會存在性能問題束析,所以開發(fā)過程中一般不使用循環(huán)套循環(huán)艳馒。
PBI中如果出現(xiàn)循環(huán)套循環(huán)的情況憎亚,只有里邊的循環(huán)會被優(yōu)化员寇,外邊的循環(huán)無法被優(yōu)化。同時會把內(nèi)循環(huán)的結(jié)果作為一個臨時表存在內(nèi)存中第美。因此會降低性能并占用過高的內(nèi)存蝶锋。
Rankx
RANKX ( <Table>, <Expression> [, <Value>] [, <Order>] [, <Ties>] )
- 第一個參數(shù)和第二個參數(shù)構(gòu)成一個lookup表,然后使用第三個參數(shù)在lookup表中尋找什往,最后返回查找到的順序(index扳缕?)。如果第三個參數(shù)省略别威,那么就使用第二個參數(shù)作為lookup的輸入?yún)?shù)躯舔。比如SaleQty按照品牌排序,第一個參數(shù)就是所有的或者所有選擇的品牌表省古,然后在這個表中添加SalesQty進行累計匯總粥庄,以便構(gòu)建lookup表,之后使用context的SalesQty在lookup表中尋找豺妓,最后返回排位惜互。
Rankx(All(Product[Brand]),SaleQty,SalesQty)簡化為Rankx(All(Product[Brand]),SaleQty) - 如果排位不是按照匯總的SalesQty進行累計布讹,比如銷售總體分為5檔,然后計算每個品牌的銷售分別屬于五檔中的哪一檔训堆。這個時候第一個參數(shù)使用的不再是按照品牌進行累計的匯總表描验,而是使用的分檔的銷售額表,第二個參數(shù)就是這個分檔的銷售額表中的銷售額坑鱼,第三個參數(shù)即lookup的參數(shù)就是SalesQty膘流,即需要排序的參數(shù)。
Rankx(檔位,檔位[銷售額],SaleQty)
最后一個參數(shù)的意思是鲁沥,如果兩個品牌的銷售額一樣睡扬,那么怎么排序呢?這個時候這兩個品牌的排位順序肯定是一致的黍析,比如都是第5位卖怜。最后一個參數(shù)的區(qū)別就在一這個第5位之后應(yīng)該是第6位還是第7位。最后一個參數(shù)是Skip或者Dense,如果選擇Skip的話阐枣,那么下一位就是第7位马靠,如果使用Dense的話,下一位就是第6位蔼两。
即:
第八章
DAX Date table template https://github.com/sql-bi/DaxDateTemplate
Part 1
Sales Amount YTD =
VAR LastVisibleDate = MAX ( 'Date'[Date] )
VAR CurrentYear = YEAR ( LastVisibleDate )
VAR SetOfDateesYtd =
FILTER (
ALL ( 'Date' ),
AND (
'Date'[Date] <= LastVisibleDate,
YEAR ( 'Date'[Date] ) = CurrentYear
)
)
VAR Result =
CALCULATE (
SUMX ( Sales, Sales[Net Price] * Sales[Quantity] ),
SetOfDateesYtd
)
RETURN
Result
Part 2
Sales Amount YTD2 =
VAR LastVisibleDate = MAX ( 'Date'[Date] )
VAR CurrentYear = YEAR ( LastVisibleDate )
VAR SetOfDateesYTD =
FILTER (
ALL ( 'Date'[Date]),
AND (
'Date'[Date] <= LastVisibleDate,
YEAR ( 'Date'[Date] ) = CurrentYear
)
)
VAR Result =
CALCULATE (
SUMX ( Sales, Sales[Net Price] * Sales[Quantity] ),
SetOfDateesYTD
)
RETURN
Result
唯一的差別在于All('Date')和All('Date'[Date]),當(dāng)使用的key是datekey連接的時候確實結(jié)果不一樣甩鳄。
原因在于All(Date[Date])只是去掉了Date這個字段的過濾,并沒有去掉Year和Month上邊的過濾器额划,而All(Date)是去掉了Date這個表上的所有過濾器妙啃;也就是說對于4月份那一行來說,默認(rèn)的過濾器為年=2017俊戳,月=4揖赴,All(Date[Date])是沒有辦法去掉這個過濾器的,也就導(dǎo)致了Sales Amount YTD2計算的仍然是4月份的數(shù)據(jù)抑胎,而Sales Amount YTD是把Date上的所有過濾去給去掉之后計算的燥滑,因此能夠得到Y(jié)TD的數(shù)據(jù)。
count1 = CALCULATE(COUNT('Date'[Date]),ALL('Date'[Date]))
count2 = CALCULATE(COUNT('Date'[Date]),ALL('Date'))
count3 = CALCULATE(COUNT('Date'[Date]))
按照邏輯來講阿逃,如果這個時候把Date表變成日期表铭拧,那么上邊這個count的結(jié)果應(yīng)該一樣的,但事實并非如此恃锉,等等在研究吧搀菩。
DaxDateTemplate
Date相關(guān)的函數(shù)及邏輯
第九章 Calculation Group
不好用,等待集成到PBI中再說吧破托。
第十章 Working with filter context
PRODUCTX ( Years, 1 + Inflation )
這個挺有意思的肪跋。
VALUES vs FILTERS
對于只有一個filter的情況下,兩個返回的值是一樣的炼团,但是當(dāng)有多個filter存在澎嚣,并且是對于其他字段進行過濾的條件下疏尿,VALUES返回的是這多個過濾條件聯(lián)合作用下,當(dāng)前字段還擁有的值易桃。而FILTERS返回的是對于當(dāng)前字段所添加的過濾選擇褥琐。或者可以說VALUES是對事實的統(tǒng)計,而FILTERS是對動作的統(tǒng)計.
比如字段A和B,現(xiàn)在對A進行過濾晤郑,但是對B進行Values和Filters檢驗敌呈,這種情況下,Values是返回在對A進行過濾之后B還剩下的值造寝,而Filters只是檢驗B上邊是否添加了filter磕洪,所以這個時候不管A做了任何的過濾,F(xiàn)ilters顯示的是B所有的值诫龙。
HASONEVALUE VS HASONEFILTER同樣的道理.
ALLEXPECT VS ALL/VALUE
從這里開始會比較容易的發(fā)現(xiàn),其實PBI的復(fù)雜之處都是在一些細枝末節(jié),大的方向其實學(xué)習(xí)起來會很簡單,但是對于細枝末節(jié)的東西或者說隱藏于其中的東西有太多了.如果稍微不注意,真的是很容易導(dǎo)致結(jié)果的錯誤,所以相對的后期的學(xué)習(xí)曲線還是比較陡的,對于IT可能需要很長時間的學(xué)習(xí)和分辨,但是對于用戶,還真是一個比較難得問題.
第十一章 Handling Hierarchy
ISINSCOPE ()析显,返回值為Ture或者False,用來判斷給定的列是否是層次結(jié)構(gòu)中的當(dāng)前層签赃。
該章節(jié)其他內(nèi)容主要講的就是如何從一個平面表重構(gòu)出一個層次結(jié)構(gòu)谷异,主要邏輯就是利用父節(jié)點和子節(jié)點編號的對應(yīng)關(guān)系,從而構(gòu)建出具體層級節(jié)點的名稱锦聊。但是有一點無奈的就是需要指定最深的層數(shù)歹嘹,也就是說需要提前計算好層數(shù),然后根據(jù)層數(shù)添加對應(yīng)的層級列到主數(shù)據(jù)表中孔庭。
剩下的主要是在討論尺上,當(dāng)層次結(jié)構(gòu)不滿的時候,下層的信息要如何正確的隱藏掉圆到。
主要用到的函數(shù)有怎抛,
PATH(<ID_columnName>, <parent_columnName>) ,用戶構(gòu)建從根節(jié)點到葉節(jié)點的全路徑构资;
LOOKUPVALUE(<result_columnName>, <search_columnName>,<search_value>)抽诉,根據(jù)指定的值獲取對應(yīng)列的相對應(yīng)內(nèi)容,相當(dāng)于VLOOPUP吐绵;
PATHITEM(<path>, <position>[, <type>]) ,獲取指定層數(shù)的節(jié)點名稱河绽;
PATHLENGTH(<path>) 己单,獲取層級的長度,用于計算某層級是否是滿層級耙饰,從而隱藏掉多余的重復(fù)信息纹笼;
其中比較繞的一點就是如果不只是葉節(jié)點帶數(shù)據(jù),層次節(jié)點也帶數(shù)據(jù)的時候苟跪,需要注意不能把這些數(shù)據(jù)給丟掉廷痘。判斷的邏輯是用最大節(jié)點+1的節(jié)點是否有數(shù)據(jù)蔓涧,同時該節(jié)點是否是最終葉節(jié)點來最終獲得這個層次節(jié)點的數(shù)據(jù)。
第十二章 Working with Tables
Filter和Calculate的區(qū)別
FILTER(<table>,<filter>)
CALCULATE(<expression>[, <filter1> [, <filter2> [, …]]])
CALCULATETABLE(<expression>[, <filter1> [, <filter2> [, …]]])
Filter的邏輯是返回指定表的子集笋额,如果表部分的參數(shù)是一個表達式的話元暴,那肯定是先計算出這個表達式的結(jié)果,之后在這個結(jié)果進行過濾以獲取部分?jǐn)?shù)據(jù)兄猩。
Calculate以及Calculate Table的邏輯是在后邊的過濾邏輯之上茉盏,Evaluate前邊的表達式以計算對應(yīng)的結(jié)果。
不從是否傳遞Context Filter的層面枢冤,但從計算邏輯層面來講鸠姨,兩者的計算邏輯就是不一致的,所以結(jié)果大部分情況下應(yīng)該也是不一致的淹真。
這個邏輯理解起來是沒有問題讶迁,但是比較有意思地方在于如果就是想用Filter的情況下,如何得到與Calculate Table一樣的結(jié)果呢核蘸。
書中提供的解決方式是引用Calculate添瓷,下邊的公式可以直接返回一個表,這個表中包含了所有的顏色值纱,以及對應(yīng)的count數(shù)鳞贷。
ADDCOLUMNS (VALUES ( 'Product'[Color] ),"Num of Products", CALCULATE (COUNTROWS ('Product' ) ))
但是對于這個公式,就出現(xiàn)了一個新問題虐唠,有沒有其他辦法獲取顏色列以及對應(yīng)的行數(shù)呢搀愧?
https://www.sqlbi.com/articles/best-practices-using-summarize-and-addcolumns/
這個鏈接中給出了一定的比較和解釋,其中關(guān)鍵的一點應(yīng)該是兩個表沒有關(guān)聯(lián)關(guān)系疆偿。
但是對于下邊的公式咱筛,是否還有其他解決方案?目前水平不夠杆故,還沒想出其他方法迅箩。
ADDCOLUMNS (VALUES ( 'Product'[Color] ),"Num of Products",COUNTROWS ('Product' ))
這里的Running Total還有點想不通。处铛。饲趋。
VAR TotalSales = [Sales Amount]
VAR ProdsWithSales =
ADDCOLUMNS (
VALUES ( 'Product'[Product Name] ),
"ProductSales", [Sales Amount]
)
VAR ProdsWithRT =
ADDCOLUMNS (
ProdsWithSales,
"RunningTotal",
VAR SalesOfCurrentProduct = [ProductSales]
RETURN
SUMX (
FILTER (
ProdsWithSales,
[ProductSales] >= SalesOfCurrentProduct
--關(guān)鍵之處,如過換成<=的話就是從小到大的匯總撤蟆,但如果是空白的話=>的情況下會有值奕塑,<=的情況下為空,
--因為小于等于空白的還是空白家肯,而大于等于空白的就相當(dāng)于所有的匯總
--高明龄砰。。。
),
[ProductSales]
)
)
VAR Top15Percent =
FILTER (
ProdsWithRT,
[RunningTotal] / TotalSales <= 0.15
--這里的TotalSales是總的Sales换棚,不是Measure自動引入Calcualte么式镐?為什么會變成總sales?
--同樣是[Sales Amount],只不過一個是定義在外邊的固蚤,一個是在里邊直接引用的
--難道是因為定義的變量是在最外邊的娘汞,所以的得到的就是匯總的?而變量內(nèi)部引用的雖然也是[Sales Amount]颇蜡,但是會傳遞context价说?
)
RETURN Top15Percent
FIND is case-sensitive, while SEARCH is not.x