PowerBI之DAX神功:第1卷第9回 基礎(chǔ)表函數(shù)之VALUES與DISTINCT函數(shù)和空行
? ? ? ? 上節(jié)課的ALL函數(shù)在今后的課程上還會(huì)經(jīng)常拿出來(lái)講,大家需要慢慢吸收。本節(jié)課的知識(shí),只要你遵循數(shù)據(jù)庫(kù)原理,表格都是1對(duì)多關(guān)系,1端主鍵不為空不重復(fù),且1端主鍵元素?cái)?shù)大于等于多端外鍵的元素去重后的個(gè)數(shù)(數(shù)據(jù)庫(kù):實(shí)時(shí)參照完整性),可以當(dāng)本節(jié)課就是在浪費(fèi)時(shí)間。只是《The Definitive Guide to DAX》舉了例子,國(guó)內(nèi)就有人依此抬扛,并且組建了DAX原理大軍。

如圖1-9-1,1端表姓名有3個(gè)人,多端表姓名有4個(gè)人,這是1對(duì)多,但它是典型的實(shí)時(shí)參照不匹配。接下來(lái)我們主要是在這種情況下舉例:

VALUES與DISTINCT函數(shù)都是表函數(shù),返回的都是一張表
參數(shù)有兩種情況:
VALUES(列)? 、 VALUES(表)
DISINCT(列)? 、DISTINCT(表)
我們先來(lái)看參數(shù)是列的情況:
DISTINCT(列):對(duì)某列去重,返回一張單列的表,他不會(huì)考慮表之間的關(guān)系問(wèn)題。
我們分別對(duì)多端表和一端表,使用【新建表】:
表1 = DISTINCT('開(kāi)房記錄表'[姓名])

表2 = DISTINCT('某女男朋友'[姓名])


VALUES(列):對(duì)某列去重,返回一張單列的表,他會(huì)判斷是否關(guān)系正常,如果實(shí)時(shí)參照不匹配會(huì)返回空行。
會(huì)有兩種情況:
1.如果這兩張表沒(méi)有關(guān)系,效果等同于DISTINCT(列)

表3 = Values('開(kāi)房記錄表'[姓名])

表4 = Values('開(kāi)房記錄表'[姓名])

2.如果這兩張表是正常的一對(duì)多關(guān)系,這時(shí)又會(huì)有兩種情況

情況1:一端姓名3個(gè)人,多端姓名3個(gè)人,一端主鍵人數(shù)大于等于多端姓名人數(shù)。效果等同于DISTINCT(列)

表5 = Values('開(kāi)房記錄表'[姓名])

表6 = Values('開(kāi)房記錄表'[姓名])

【重點(diǎn)】情況2:一端主鍵小于多端外鍵數(shù)量,例如1端只有3個(gè)人,而多端有4個(gè)人。

? ? ? ?某女男朋友分別是張三,李四,王五,但是她突然與一個(gè)不認(rèn)識(shí)的人叫吳刷的開(kāi)房了,這種情況,他們的關(guān)系有問(wèn)題,是否違法,需由有關(guān)部門(mén)調(diào)查。我們討論的不是法律問(wèn)題,而是遇到這種問(wèn)題時(shí),誰(shuí)來(lái)發(fā)出預(yù)警?答:Values
表7 = Values('開(kāi)房記錄表'[姓名])

表8 = Values('某女男朋友'[姓名])

? ? ? ? 其實(shí),繞了這么一大圈就是表8出問(wèn)題了。這里多了一個(gè)空,而這個(gè)空,就是告訴你,有一個(gè)或多個(gè)跟她開(kāi)過(guò)房的人其實(shí)她們并不認(rèn)識(shí)。請(qǐng)有關(guān)部門(mén)調(diào)查。
? ? ? ? 當(dāng)你的表出現(xiàn)這種情況時(shí),就是告訴你,你的1對(duì)多關(guān)系中,出現(xiàn)了實(shí)時(shí)參照不匹配的情況,請(qǐng)檢查表格。
? ? ? ? 假設(shè),你開(kāi)一個(gè)小賣(mài)部,你只賣(mài)食品,你的商品表中也只登記了這相關(guān)食品,但是你在銷(xiāo)售記錄中發(fā)現(xiàn)了「骨灰盒」、「壽衣」之類(lèi)的銷(xiāo)售時(shí),趕快抽自己一個(gè)大嘴巴,上班要遲到了。
? ? ? ? 再舉個(gè)例子,華為專(zhuān)賣(mài)店,只賣(mài)華為產(chǎn)品,你拿著一臺(tái)新買(mǎi)的小米手機(jī),讓他們用POS掃一下,看看它多少錢(qián)?掃描結(jié)果是沒(méi)有此商品,因?yàn)槿思乙欢吮碇袥](méi)有小米手機(jī)的信息。
? ? ? ? 我在2020年6月《PowerBI基礎(chǔ)篇重制版》里面跟大家說(shuō),建議使用SQL拿到一張干凈的表,你就可以避開(kāi)99%的原理。如果不是多表連線,這兩個(gè)函數(shù)在參數(shù)是列的時(shí)候就沒(méi)有區(qū)別。

接下來(lái),我們看一下他的應(yīng)用:
大家都知道聚合函數(shù)CountRows參數(shù)是一張表,之前我們可以用Filter篩選表或ALL全選表,通過(guò)縮小或擴(kuò)大表的范圍后放到CountRows(表)里面計(jì)算行數(shù)。
如果我們只想計(jì)算某個(gè)表中的某個(gè)列它去重之后的行數(shù)。這個(gè)時(shí)候我們就用到了Values或DISTINCT。我們以實(shí)時(shí)參照不匹配舉例:


新建度量值,并放到矩陣中:
D行數(shù) = countrows(DISTINCT('某女男朋友'[姓名]) )
V行數(shù) = countrows(VALUES('某女男朋友'[姓名]) )

? ? ? ? 如上圖,當(dāng)矩陣行標(biāo)題是多端表中的姓名時(shí),多端不能篩選一端,所有度量值沒(méi)有篩選功能,但是由于Values檢測(cè)到實(shí)時(shí)參照不匹配的情況,多了一個(gè)空行,它的總行數(shù)就是4,而DISTINCT的總行數(shù)就是3。

? ? ? ? 如上圖,當(dāng)矩陣行標(biāo)題是一端表中的姓名時(shí),可以篩選了,Values檢測(cè)到實(shí)時(shí)參照不匹配的情況,多了一個(gè)空行,它的總行數(shù)就是4,篩選后每個(gè)人都是1,而DISTINCT的總行數(shù)就是3。
? ? ? ? 當(dāng)出現(xiàn)實(shí)時(shí)參照不匹配的時(shí)候,如果我們需要不顯示這個(gè)空行,就會(huì)用到DISTINCT(列)。

? ? ? ? 開(kāi)始時(shí)就告訴大家,ALL函數(shù)以后要講的地方多了去了,這節(jié)課我們就再講講,其它ALL(列)與Values(列)只是功能不同,前者是全選,后者是去重。但是,它們有一個(gè)共同點(diǎn):都會(huì)考慮是否出現(xiàn)了實(shí)時(shí)參照不匹配情況,如果出現(xiàn)了,就會(huì)在你all(一端表[列名])時(shí),出現(xiàn)空行。
我們可以使用《火力全開(kāi)》筆記第8課講的ALLNOBLANKROW函數(shù)處理空行問(wèn)題。
ALL(列)? 與??ALLNOBLANKROW(列)
Values(列) 與?DISTINCT(列)
左邊函數(shù)會(huì)檢測(cè)空行,右邊函數(shù)會(huì)忽略檢測(cè)。
我們寫(xiě)兩個(gè)度量值:
all行數(shù) = countrows(all('某女男朋友'[姓名]) )
ALLNOBLANKROW行數(shù) = countrows(ALLNOBLANKROW('某女男朋友'[姓名]) )

? ? ? ? 如上圖所示,我們使用卡片圖展示兩個(gè)度量值的結(jié)果,all行數(shù) =4,因?yàn)樗鼨z測(cè)到了實(shí)時(shí)參照不匹配,產(chǎn)生了一個(gè)空行。而ALLNOBLANKROW行數(shù)忽略了檢測(cè),返回的就是3。
? ? ? ? 這里給大家講一個(gè)故事:2020年10月7日我20歲生日當(dāng)天晚上,DAX原理之父某楓講師1分鐘內(nèi)在我的powerbI所有視頻下留言,稱(chēng)我不講原理是坑人誤導(dǎo)人。后來(lái)我看了一下他講的內(nèi)容,完全是看完《The Definitive Guide to DAX》著魔了,書(shū)中確實(shí)是這樣講的,但是在實(shí)際工作中,一對(duì)多關(guān)系,是要尊尋實(shí)際參照完整性的,沒(méi)有意義的事情我何必在新手小白的課程中反復(fù)強(qiáng)調(diào)呢?數(shù)據(jù)庫(kù)的基礎(chǔ)知識(shí)很重要,不懂?dāng)?shù)據(jù)庫(kù),必會(huì)走火入魔。
并不是所有事都可以拿來(lái)抬扛,我曾經(jīng)在知乎上給部分講師講過(guò)一個(gè)道理:
? ? ? ? 假設(shè)有一個(gè)叫吳刷的人,正在被警方圍剿,這時(shí)他突然原地起飛,飛出地球之外。注意細(xì)節(jié),他是原地起飛。高度不影響經(jīng)緯度。那么他這種行為,在沒(méi)有改變經(jīng)緯度的情況算不算逃跑呢?如果是羅老師講法,我們可以研究探討。如果今天要執(zhí)行抓捕行動(dòng),你問(wèn)領(lǐng)導(dǎo)遇到這種情況,我可不可以采取必要措施,領(lǐng)導(dǎo)可能會(huì)說(shuō)你科幻電影看多了。

剛才我們說(shuō)了參數(shù)為列的情況,現(xiàn)在我們說(shuō)說(shuō)參數(shù)為表的情況:
DISTINCT(表)? :只有每個(gè)列都重復(fù),才會(huì)去重。

DISTINCT表 = countrows(DISTINCT('開(kāi)房記錄表'))
《The Definitive Guide to DAX》上面的解釋翻譯成中文:對(duì)表去重但是不考慮空行。
? ? ? ? 剛才你們是否發(fā)現(xiàn)了一個(gè)問(wèn)題,Values(1端表[列]) 才會(huì)有空行的問(wèn)題,Values(多端表[列])沒(méi)有空行問(wèn)題,因?yàn)闄z測(cè)實(shí)時(shí)參照不匹配的問(wèn)題,是從一端檢測(cè)多端的。
? ? ? ? 我們只會(huì)將DISTINCT函數(shù)用到多端表上,一端特點(diǎn)是什么?答:主鍵不為空不重復(fù)。那么你用DISTINCT(1端表)和直接用這張1端表有什么區(qū)別呢?根本就沒(méi)有重復(fù),談何去重?既然我們不應(yīng)用到一端,又談何檢測(cè)實(shí)時(shí)參照不匹配呢?
總結(jié):
DISTINCT(表)? :只有每個(gè)列都重復(fù),才會(huì)去重。
? ? ? ? 這就是喜歡英語(yǔ)和喜歡數(shù)學(xué)的區(qū)別,擁有邏輯思維的人,不會(huì)全信任何書(shū)籍,要自己測(cè)試,依據(jù)事實(shí)說(shuō)話。

Values(表)?:復(fù)制一張表,但是當(dāng)參數(shù)是一端表時(shí),會(huì)考慮實(shí)時(shí)參照不匹配。反之,參數(shù)是多端時(shí)就不會(huì)考慮了。
VALUES表 = Countrows(VALUES('某女男朋友'))

你看出現(xiàn)空行了吧?同理,ALL(表)也會(huì)遇到同樣問(wèn)題,我們會(huì)使用ALLNOBLANKROW(表)處理,詳見(jiàn)《火力全開(kāi)》筆記第8課

忠告:別研究這些沒(méi)用的東西,你只要正確建立表和表關(guān)系,一對(duì)多關(guān)系,主鍵不為空不重復(fù),一端主鍵永遠(yuǎn)不小于多端外鍵。滿(mǎn)足了這個(gè)條件后,原理就變簡(jiǎn)單了,就可以用以下語(yǔ)言代替:
Values和Distinct當(dāng)參數(shù)為列時(shí),都是返回去重后的單列表。
(指定多列去重我們以后再講,這兩個(gè)函數(shù)只支持一個(gè)參數(shù),不支持指定多列去重)