多對多關聯性指導
此文章以使用 Power BI Desktop 的資料模型製作人員為目標。 其描述三種不同的多對多模型化案例。 此外,也為您提供如何在模型中成功進行設計的相關指導。
注意
本文並未涵蓋模型關聯性簡介。 如果您對關聯性、其屬性或如何進行設定不是很熟悉,建議您先閱讀 Power BI Desktop 中的模型關聯性一文。
您也必須了解星型結構描述設計。 如需詳細資訊,請參閱了解星型結構描述及其對 Power BI 的重要性。
事實上,有三種多對多案例。 可能會在您需要執行下列動作時發生:
- 建立兩個維度類型資料表的關聯
- 建立兩個事實類型資料表的關聯
- 當事實類型資料表是以比維度類型資料表資料列更高的資料粒度來儲存資料列時,建立更高資料粒度事實類型資料表的關聯
注意
Power BI 目前原生支援多對多關聯性。 如需詳細資訊,請參閱在 Power BI Desktop 中套用多對多關聯性。
建立多對多維度的關聯
讓我們舉一個例子來探討第一種多對多案例類型。 此傳統案例會建立下列兩個實體的關聯:銀行客戶和銀行帳戶。 假設客戶可以有多個帳戶,而帳戶可以有多個客戶。 當帳戶有多個客戶時,通常稱為「聯合帳戶持有人」。
建立這些實體的模型相當簡單。 一個維度類型資料表會儲存帳戶,另一個維度類型資料表則會儲存客戶。 維度類型資料表的特性是,每個資料表中都有一個識別碼資料行。 若要建立這兩個資料表之間關聯性的模型,則需要第三個資料表。 此資料表通常稱為「橋接資料表」。 在此範例中,其用途是為了將每個客戶/帳戶關聯儲存為一個資料列。 有趣的是,當此資料表只包含識別碼資料行時,則稱為非事實資料表。
以下是這三個資料表的簡化模型圖表。
第一個資料表的名稱為 Account,其中包含兩個資料行:AccountID 和 Account。 第二個資料表的名稱為 AccountCustomer,其中包含兩個資料行:AccountID 和 CustomerID。 第三個資料表的名稱為 Customer,其中包含兩個資料行:CustomerID 和 Customer。 任何資料表之間都不存在關聯性。
新增了兩個一對多關聯性來建立資料表的關聯。 以下是相關資料表的更新模型圖表。 新增了名為 [交易] 的事實類型資料表。 其記錄帳戶交易。 橋接資料表和所有識別碼資料行都已隱藏。
為了協助描述關聯性篩選傳播的運作方式,此模型圖表已修改為顯示資料表資料列。
注意
您無法在 Power BI Desktop 模型圖表中顯示資料表資料列。 在本文中,為了以清楚的範例來支援討論,已事先完成。
下列項目符號清單描述這四個資料表的資料列詳細資料:
- [帳戶] 資料表有兩個資料列:
- [帳戶識別碼] 1 表示「帳戶-01」
- [帳戶識別碼] 2 表示「帳戶-02」
- [客戶] 資料表有兩個資料列:
- [客戶識別碼] 91 表示「客戶-91」
- [客戶識別碼] 92 表示「客戶-92」
- [帳戶客戶] 資料表有三個資料列:
- [帳戶識別碼] 1 與 [客戶識別碼] 91 建立關聯
- [帳戶識別碼] 1 與 [客戶識別碼] 92 建立關聯
- [帳戶識別碼] 2 與 [客戶識別碼] 92 建立關聯
- [交易] 資料表有三個資料列:
- [日期] 2019 年 1 月 1 日、[帳戶識別碼] 1、[金額] 100
- [日期] 2019 年 2 月 2 日、[帳戶識別碼] 2、[金額] 200
- [日期] 2019 年 3 月 3 日、[帳戶識別碼] 1、[金額] -25
讓我們來看一下查詢模型時所發生的情況。
以下是摘要 [交易] 資料表中 [金額] 資料行的兩個視覺效果。 第一個視覺效果是依帳戶分組,因此 [金額] 資料行的總和表示「帳戶餘額」。 第二個視覺效果是依客戶分組,因此 [金額] 資料行的總和表示「客戶餘額」。
第一個視覺效果的標題為 [帳戶餘額],其中包含兩個資料行:帳戶和金額。 其顯示下列結果:
- 「帳戶-01」的餘額為 75
- 「帳戶-02」的餘額為 200
- 總計為 275
第二個視覺效果的標題為 [客戶餘額],其中包含兩個資料行:客戶和金額。 其顯示下列結果:
- 「客戶-91」的餘額為 275
- 「客戶-92」的餘額為 275
- 總計為 275
快速看一下資料表資料列,[帳戶餘額] 視覺效果顯示每個帳戶和總金額的結果正確。 這是因為每個帳戶分組都會導致篩選傳播至該帳戶的 [交易] 資料表。
不過,[客戶餘額] 視覺效果則不太正確。 [客戶餘額] 視覺效果中每個客戶的餘額都與總餘額相同。 只有在每個客戶都是每個帳戶的聯合帳戶持有人時,此結果才正確。 但在此範例中並非如此。 該問題與篩選傳播有關。 其並未完全流向 [交易] 資料表。
沿著 [客戶] 資料表到 [交易] 資料表的關聯性篩選方向。 [帳戶] 與 [帳戶客戶] 資料表之間的關聯性傳播方向明顯有誤。 此關聯性的篩選方向必須設定為 [雙向]。
如預期般,[帳戶餘額] 視覺效果並未進行任何變更。
不過,[客戶餘額] 視覺效果現在會顯示下列結果:
- 「客戶-91」的餘額為 75
- 「客戶-92」的餘額為 275
- 總計為 275
[客戶餘額] 視覺效果現在會顯示正確的結果。 您可以自行沿著篩選方向,並查看客戶餘額是如何計算。 此外,請了解視覺效果總計表示「所有客戶」。
不熟悉模型關聯性的人可能會認為結果不正確。 他們可能會問:為什麼「客戶-91」和「客戶-92」的總餘額等於 350 (75 + 275)?
其問題的答案在於了解多對多關聯性。 每個客戶餘額可能表示多個帳戶餘額的相加,因此客戶餘額「非加法運算」。
建立多對多維度的關聯指導
當維度類型資料表之間有多對多關聯性時,我們提供下列指導:
- 針對每個多對多相關實體,各新增為一個模型資料表,以確保其具有唯一的識別碼資料行
- 新增橋接資料表以儲存相關聯的實體
- 建立這三個資料表之間的一對多關聯性
- 設定一個雙向關聯性,以允許篩選傳播接續到事實類型資料表
- 在遺漏識別碼值不當的情況下,請將識別碼資料行的 [可為 Null] 屬性設定為 FALSE;如果以遺漏值為來源,則資料重新整理將會失敗
- 隱藏橋接資料表 (除非其中包含需要報告的其他資料行或量值)
- 隱藏不適合報告的任何識別碼資料行 (例如,當識別碼為 Surrogate 索引鍵時)
- 如果識別碼資料行必須保持可見,請確定其位於關聯性的「一」端;請一律隱藏「多」端的資料行。 這會產生最佳的篩選效能。
- 為了避免混淆或誤解,請傳達說明給您的報表使用者;您可以透過文字方塊或視覺效果標題工具提示來新增描述
不建議您直接建立多對多維度類型資料表的關聯。 這種設計方法需要設定具有多對多基數的關聯性。 雖然在概念上可達成此目的,但這表示相關資料行將會包含重複的值。 廣為接受的設計做法是讓維度類型資料表具有一個識別碼資料行。 維度類型資料表應該一律使用識別碼資料行作為關聯性的「一」端。
建立多對多事實的關聯
第二種多對多案例類型涉及建立兩個事實類型資料表的關聯。 兩個事實類型資料表可以直接相關聯。 這種設計技術有助於快速且簡單的資料探索。 不過,我們必須明確指出,通常不建議採用這種設計方法。 本節稍後將說明原因。
讓我們參考一個範例,其涉及兩個事實類型資料表:訂單和履行。 [訂單] 資料表會針對每個訂單明細各包含一個資料列,而 [履行] 資料表則會針對每個訂單明細各包含零個 (含) 以上的資料列。 [訂單] 資料表中的資料列表示銷售訂單。 [履行] 資料表中的資料列表示已出貨的訂單項目。 多對多關聯性會建立兩個 [訂單識別碼] 資料行的關聯,但只有來自 [訂單] 資料表的篩選傳播 ([訂單] 會篩選 [履行])。
關聯性基數會設定為多對多,以支援在這兩個資料表中儲存重複的 [訂單識別碼] 值。 在 [訂單] 資料表中,由於訂單可能會有多個明細,因此可能存在重複的 [訂單識別碼] 值。 在 [履行] 資料表中,由於訂單可能會有多個明細,且訂單明細可能會透過多次出貨來履行,因此可能存在重複的 [訂單識別碼] 值。
現在讓我們看一下資料表資料列。 在 [履行] 資料表中,請注意訂單明細可能會透過多次出貨來履行 (沒有訂單明細表示訂單尚未履行)。
下列項目符號清單描述這兩個資料表的資料列詳細資料:
- [訂單] 資料表包含五個資料列:
- [訂單日期] 2019 年 1 月 1 日、[訂單識別碼] 1、[訂單明細] 1、[產品識別碼] Prod-A、[訂單數量] 5、[銷售量] 50
- [訂單日期] 2019 年 1 月 1 日、[訂單識別碼] 1、[訂單明細] 2、[產品識別碼] Prod-B、[訂單數量] 10、[銷售量] 80
- [訂單日期] 2019 年 2 月 2 日、[訂單識別碼] 2、[訂單明細] 1、[產品識別碼] Prod-B、[訂單數量] 5、[銷售量] 40
- [訂單日期] 2019 年 2 月 2 日、[訂單識別碼] 2、[訂單明細] 2、[產品識別碼] Prod-C、[訂單數量] 1、[銷售量] 20
- [訂單日期] 2019 年 3 月 3 日、[訂單識別碼] 3、[訂單明細] 1、[產品識別碼] Prod-C、[訂單數量] 5、[銷售量] 100
- [履行] 資料表包含四個資料列:
- [履行日期] 2019 年 1 月 1 日、[履行識別碼] 50、[訂單識別碼] 1、[訂單明細] 1、[履行數量] 2
- [履行日期] 2019 年 2 月 2 日、[履行識別碼] 51、[訂單識別碼] 2、[訂單明細] 1、[履行數量] 5
- [履行日期] 2019 年 2 月 2 日、[履行識別碼] 52、[訂單識別碼] 1、[訂單明細] 1、[履行數量] 3
- [履行日期] 2019 年 1 月 1 日、[履行識別碼] 53、[訂單識別碼] 1、[訂單明細] 2、[履行數量] 10
讓我們來看一下查詢模型時所發生的情況。 以下是依 [訂單] 資料表 [訂單識別碼] 資料行來比較訂單和履行數量的資料表視覺效果。
此視覺效果會呈現正確的結果。 不過,模型的實用性會受到限制;您只能依 [訂單] 資料表 [訂單識別碼] 資料行進行篩選或分組。
建立多對多事實的關聯指導
一般而言,不建議使用多對多基數來直接建立兩個事實類型資料表的關聯。 主要原因是因為該模型的彈性不如您報告視覺效果篩選或分組的方式。 在此範例中,視覺效果只能依 [訂單] 資料表 [訂單識別碼] 資料行進行篩選或分組。 另一個原因與您資料的品質有關。 如果您的資料有完整性問題,有可能是因為在查詢期間因「有限關聯性」的本質,而省略一些資料列。 如需詳細資訊,請參閱 Power BI Desktop 中的模型關聯性 (關聯性評估)。
建議您採用星型結構描述設計原則,而不是直接建立事實類型資料表的關聯。 做法是新增兩個維度類型資料表。 然後使用一對多關聯性,將維度類型資料表關聯到事實類型資料表。 這種設計方法強大之處在於提供彈性的報告選項。 這讓您可以使用任何維度類型資料行來進行篩選或分組,以及摘要任何相關事實類型資料表。
讓我們來看一個更好的解決方案。
請注意下列設計變更:
- 此模型現在有四個額外的資料表:OrderLine、OrderDate、Product 和 FulfillmentDate
- 這四個額外的資料表全部都是維度類型資料表,並使用一對多關聯性,將這些資料表關聯到事實類型資料表
- [訂單明細] 資料表包含 [訂單明細識別碼] 資料行,表示 [訂單識別碼] 值乘以 100,加上 [訂單明細] 值的結果;這是每個訂單明細的唯一識別碼
- [訂單] 和 [履行] 資料表現在包含 [訂單明細識別碼] 資料行,而不再包含 [訂單識別碼] 和 [訂單明細] 資料行
- [履行] 資料表現在包含 [訂單日期] 和 [產品識別碼] 資料行
- [履行日期] 資料表只會與 [履行] 資料表相關聯
- 所有唯一識別碼資料行都已隱藏
花點時間套用星型結構描述設計原則會提供下列優點:
- 您的報表視覺效果可依維度類型資料表中任何可見資料行進行「篩選或分組」
- 您的報表視覺效果可「摘要」事實類型資料表中任何可見資料行
- 套用至 [訂單明細]、[訂單日期] 或 [產品] 資料表的篩選會傳播至這兩個事實類型資料表
- 所有關聯性都是一對多,而且每個關聯性都是「一般關聯性」。 資料完整性問題不會被隱藏。 如需詳細資訊,請參閱 Power BI Desktop 中的模型關聯性 (關聯性評估)。
建立更高資料粒度事實的關聯
此多對多案例與本文中已描述的其他兩個案例非常不同。
讓我們考慮牽涉四個資料表的範例:Date、Sales、Product 和 Target。 [日期] 和 [產品] 是維度類型資料表,並使用一對多關聯性,將每個資料表關聯到 [銷售量] 事實類型資料表。 到目前為止,這是不錯的星型結構描述設計。 不過,[目標] 資料表尚未與其他資料表相關聯。
Target 資料表包含三個資料行:Category、TargetQuantity 和 TargetYear。 資料表資料列顯示年份和產品類別的資料粒度。 換句話說,目標 (用來測量銷售績效) 會每年針對每個產品類別進行設定。
由於 [目標] 資料表是以比維度類型資料表更高的層級來儲存資料,因此無法建立一對多關聯性。 沒錯,只有其中一個關聯性才適用。 讓我們來探索如何將 [目標] 資料表關聯到維度類型資料表。
建立更高資料粒度時間週期的關聯
[日期] 與 [目標] 資料表之間的關聯性應該是一對多關聯性。 這是因為 [目標年份] 資料行的值為日期。 在此範例中,每個 [目標年份] 資料行值都是該目標年份的第一個日期。
提示
以高於日期的時間資料粒度儲存事實時,請將資料行的資料類型設定為 [日期] (如果使用日期索引鍵,則設定為 [整數])。 在資料行中,儲存一個值來表示時間週期的第一天。 例如,年份期間會記錄為該年份的 1 月 1 日,而月份期間則會記錄為該月份的第一天。
不過,為了確保月份或日期層級篩選產生有意義的結果,請務必謹慎。 若沒有任何特殊計算邏輯,則報表視覺效果可能會報告目標日期就是每年的第一天。 所有其他日期 (及一月以外的所有月份) 都會將目標數量摘要為空白。
下列矩陣視覺效果顯示當報表使用者從某一年份鑽研到其月份時所發生的情況。 此視覺效果將會摘要 [目標數量] 資料行 (已啟用矩陣資料列的 顯示沒有資料的項目 選項)。
為了避免此行為,建議您使用量值來控制事實資料的摘要。 控制摘要其中一種方式是在查詢較低層級的時間週期時,傳回空白。 另一種方式 (使用一些複雜的 DAX 定義) 則是在較低層級的時間週期內分配值。
請考慮下列使用 ISFILTERED DAX 函式的量值定義。 只有在未篩選 [日期] 或 [月份] 資料行時,才會傳回值。
Target Quantity =
IF(
NOT ISFILTERED('Date'[Date])
&& NOT ISFILTERED('Date'[Month]),
SUM(Target[TargetQuantity])
)
下列矩陣視覺效果現在使用 [目標數量] 量值。 其顯示所有的每月目標數量都是空白。
建立更高資料粒度 (非日期) 的關聯
將維度類型資料表中的非日期資料行關聯到事實類型資料表 (而且其資料粒度高於維度類型資料表) 時,則需要採用不同的設計方法。
[類別] 資料行 (來自 [產品] 和 [目標] 資料表) 包含重複的值。 因此,一對多關聯性沒有「一」端。 在此情況下,您必須建立多對多關聯性。 此關聯性應該是從維度類型資料表到事實類型資料表的單向傳播篩選。
現在讓我們看一下資料表資料列。
在 [目標] 資料表中,有四個資料列:每個目標年份 (2019 和 2020) 各兩個資料列,分別包含兩個類別 ([服飾] 和 [配件])。 在 [產品] 資料表中,有三個產品。 其中兩個屬於 [服飾] 類別,另一個則屬於 [配件] 類別。 其中一個服飾色彩為綠色,其餘兩個則為藍色。
依 [產品] 資料表中 [類別] 資料行分組的資料表視覺效果會產生下列結果。
此視覺效果會產生正確的結果。 現在讓我們來思考當使用 [產品] 資料表中 [色彩] 資料行來分組目標數量時所發生的情況。
此視覺效果會產生錯誤陳述的資料。 這是為什麼?
篩選 [產品] 資料表中的 [色彩] 資料行會產生兩個資料列。 其中一個資料列表示 [服飾] 類別,另一個則表示 [配件] 類別。 這兩個類別的值會當作篩選值傳播至 [目標] 資料表。 換句話說,由於兩個類別的產品使用藍色,因此會使用「這些類別」來篩選目標。
如先前所述,為了避免此行為,建議您使用量值來控制事實資料的摘要。
請考慮下列量值定義。 請注意,在類別層級底下的所有 [產品] 資料表資料行都會針對篩選進行測試。
Target Quantity =
IF(
NOT ISFILTERED('Product'[ProductID])
&& NOT ISFILTERED('Product'[Product])
&& NOT ISFILTERED('Product'[Color]),
SUM(Target[TargetQuantity])
)
下列資料表視覺效果現在使用 [目標數量] 量值。 其顯示所有的色彩目標數量都是空白。
最終的模型設計看起來如下所示。
建立更高資料粒度事實的關聯指導
當您必須將維度類型資料表關聯到事實類型資料表,且事實類型資料表以比維度類型資料表資料列更高的資料粒度來儲存資料列時,我們提供下列指導:
- 針對更高資料粒度的事實日期:
- 在事實類型資料表中,儲存時間週期的第一個日期
- 建立日期資料表與事實類型資料表之間的一對多關聯性
- 針對其他更高資料粒度的事實:
- 建立維度類型資料表與事實類型資料表之間的多對多關聯性
- 針對這兩種類型:
- 使用量值邏輯控制摘要;當使用較低層級的維度類型資料行來進行篩選或分組時,傳回空白
- 隱藏可摘要的事實類型資料表資料行;如此一來,只能使用量值來摘要事實類型資料表
相關內容
如需本文的詳細資訊,請參閱下列資源: