多對多關係指引
本文針對使用 Power BI Desktop 的數據建模師的您。 它描述三個不同的多對多模型案例。 它也提供指引,說明如何在模型中成功地為這些目標設計。
注意事項
本文未涵蓋模型關聯性的簡介。 如果您不熟悉關聯性、其屬性或如何設定關聯性,建議您先閱讀 Power BI Desktop 中的 模型關聯性 一文。
您也必須瞭解星型架構設計。 如需詳細資訊,請參閱 瞭解星型架構和Power BI的重要性。
有三種不同的多對多情境。 當您需要執行某些操作時,可能會發生這些情況:
建立多對多維度之間的關聯
傳統多對多案例涉及兩個實體,例如銀行客戶和銀行帳戶。 請考慮客戶可以有多個帳戶,而帳戶可以有多個客戶。 當帳戶有多個客戶時,通常稱為 共同帳戶持有人。
將這些實體進行模型化是很簡單的。 一個 維度表 儲存帳戶,另一個則儲存客戶。 如同維度數據表的特性,每個數據表中都有唯一標識碼 (ID) 數據行。 若要建立兩個數據表之間的關聯性模型,則需要第三個數據表。 此表格通常被稱為 橋接表。 在此範例中,其目的是要為每個客戶帳戶連結儲存一個資料列。 有趣的是,當這個資料表只包含識別欄位時,它稱為 無事實的事實表。
以下是三個模型數據表的簡單圖表。
第一個資料表名為 Account
,其中包含兩個資料行:AccountID
和 Account
。 第二個資料表名為 AccountCustomer
,其中包含兩個數據行:AccountID
和 CustomerID
。 第三個資料表名為 Customer
,其中包含兩個數據行:CustomerID
和 Customer
。 任何數據表之間並不存在關聯性。
新增兩個一對多的連結來連接資料表。 以下是相關數據表的更新模型圖表。 已新增名為 Transaction
的事實數據表。 它會記錄帳戶交易。 橋接數據表和所有標識符欄都已隱藏。
為了協助描述關聯性篩選傳播的運作方式,已修改模型圖表以顯示數據表數據列。
四個資料表的數據列詳細資料會顯示在下列點符清單中:
-
Account
資料表有兩個資料列:-
AccountID
1 適用於 Account-01 -
AccountID
2 適用於 Account-02
-
-
Customer
資料表共有兩個資料列:-
CustomerID
91 適用於 Customer-91 -
CustomerID
92 用於 Customer-92
-
-
AccountCustomer
資料表有三個資料列:-
AccountID
1 與 91CustomerID
91 相關聯 -
AccountID
1 與 92CustomerID
92 相關聯 -
AccountID
2 與 92CustomerID
92 相關聯
-
-
Transaction
表格有三個列:-
Date
2019 年 1 月 1 日,AccountID
1,Amount
100 -
Date
2019 年 2 月 2 日,AccountID
2,Amount
200 -
Date
2019 年 3 月 3 日,AccountID
1,Amount
-25
-
讓我們看看查詢模型時會發生什麼事。
在下圖中,有兩個表格視覺效果總結了Transaction
表格中的 Amount
欄。 第一個視覺群組是依帳戶分組的,因此 Amount
數據行的總和代表 帳戶餘額。 依客戶排序的第二個視覺群組,因此 Amount
數據行的總和代表 客戶餘額。
第一個資料表視覺效果 (帳戶餘額) 有兩個資料行:Account
和 Amount
。 它會顯示下列結果:
- 帳戶-01 餘額金額為 75。
- 帳戶-02 的 餘額為 200。
- 總計 275。
第二個資料表的視覺化(Customer Balance)有兩個欄位:Customer
和 Amount
。 它會顯示下列結果:
- Customer-91 餘額金額 275。
- Customer-92 餘額 275。
- 總計 275。
快速瀏覽表格的數據列和帳戶餘額圖表,可以發現每個帳戶和總金額的結果都是正確的。 這是因為每個帳戶群組會導致篩選傳播至該帳戶的 Transaction
數據表。
不過,客戶餘額視圖看起來不正確。 此視覺效果中的每個客戶都有與總餘額相同的餘額。 只有當每位客戶都是每個帳戶的聯合帳戶持有人時,這個結果才能正確。 在此範例中,情況並非如此。 出現了一個問題,與過濾器傳播有關。 篩選條件不會一路流向 Transaction
數據表。
如果您遵循從 Customer
數據表到 Transaction
數據表的關聯性篩選方向,您可以判斷 Account
與 AccountCustomer
數據表之間的關聯性正以錯誤的方向傳播。 這個關聯性的篩選方向必須設定為 Both
。
如預期般,帳戶餘額視覺效果沒有任何變更。
不過,[客戶餘額] 視覺效果現在會顯示下列結果:
- Customer-91 餘額 75。
- Customer-92 的餘額 275。
- 總計:275。
[客戶餘額] 視覺效果現在會顯示正確的結果。 請自行遵循篩選指示,並查看客戶餘額的計算方式。 此外,瞭解視覺總計意味著 所有客戶。
不熟悉模型關聯性的人可能會得出結論,結果不正確。 他們可能會問:為什麼 Customer-91
Customer-92
的總餘額不等於350(75 + 275)?
他們問題的答案在於理解多對多關係。 每個客戶餘額都可以代表新增多個帳戶餘額,因此客戶餘額 非加法性。
建立多對多維度指引的關聯
當您在維度數據表之間具有多對多關聯性時,請遵循下列指引:
- 將每個多對多相關實體新增為模型資料表,確保其具有 ID 欄。
- 新增橋接數據表以儲存相關聯的實體。
- 建立三個數據表之間的一對多關聯性。
- 設定 一個 雙向關係,以便於篩選傳播繼續至事實數據表。
- 當遺漏標識碼值不合適時,請停用
Is Nullable
屬性—當來源遺漏值時,數據重新整理將會失敗。 - 隱藏橋接數據表(除非它包含報告所需的其他數據行或量值)。
- 隱藏任何不適合報告的 ID 欄位(例如,當欄位存放替代索引鍵值時)。
- 如果讓ID欄保持可見,請確定它位於關聯性的「一」端,一律隱藏「多」端的欄位。 這是因為套用至「一」投影片的篩選會產生較佳的篩選效能。
- 若要避免混淆或誤解,請將說明傳達給報表使用者—您可以使用文字框或 可視化標頭工具提示來新增描述,。
我們不建議您直接建立多對多維度數據表的關聯。 此設計方法需要建立一種多對多基數的關係。 在概念上可以達成,但它表示相關數據行可能包含重複的值。 維度數據表有一個ID欄位,這是公認的設計做法。 維度數據表應該一律使用標識符數據行作為關聯性的「一」端。
使多對多事實相關聯
不同的多對多案例類型牽涉到兩個事實數據表。 兩個事實表可以直接建立關聯。 這項設計技術對於快速且簡單的數據探索很有用。 不過,為了清楚起明,我們通常不建議使用這種設計方法。 我們將在本節稍後說明原因。
讓我們考慮一個包含兩個事實數據表的範例:Order
和 Fulfillment
。
Order
數據表包含每個訂單行一個數據列,而 Fulfillment
數據表可以包含每個訂單行的零或多個數據列。
Order
數據表中的數據列代表銷售訂單。
Fulfillment
表中的資料列代表已出貨的訂單項目。 多對多關聯性會關聯每個數據表中的 OrderID
數據行,而篩選傳播只會從 Order
數據表傳播(這表示 Order
數據表會篩選 Fulfillment
數據表)。
關聯性基數設定為 Many-to-many
,以支援在這兩個數據表中儲存重複 OrderID
數據行值。 在 Order
數據表中,可能會有重複的標識碼值,因為訂單可以有多個行。 在 Fulfillment
數據表中,可能會有重複的 ID 值,因為訂單可以有多個項目,而且這些項目可以通過許多出貨來完成。
現在讓我們看看表格的行。 在 Fulfillment
數據表中,請注意,訂單項目可以透過多個貨運來完成。 (沒有訂單行意味著訂單尚未完成。
這兩個資料表的數據列詳細資料會在下列點符清單中描述:
-
Order
表共有五列資料:-
OrderDate
2019 年 1 月 1 日,OrderID
1,OrderLine
1,ProductID
Prod-A,OrderQuantity
5,Sales
50 -
OrderDate
2019 年 1 月 1 日,OrderID
1,OrderLine
2,ProductID
Prod-B,OrderQuantity
10,Sales
80 -
OrderDate
2019 年 2 月 2 日,OrderID
2,OrderLine
1,ProductID
Prod-B,OrderQuantity
5,Sales
40 -
OrderDate
2019 年 2 月 2 日,OrderID
2,OrderLine
2,ProductID
Prod-C,OrderQuantity
1,Sales
20 -
OrderDate
2019 年 3 月 3 日OrderID
3,OrderLine
1,ProductID
Prod-C,OrderQuantity
5,Sales
100
-
-
Fulfillment
資料表有四個資料列:-
FulfillmentDate
2019 年 1 月 1 日,FulfillmentID
50,OrderID
1,OrderLine
1,FulfillmentQuantity
2 -
FulfillmentDate
2019 年 2 月 2 日,FulfillmentID
51,OrderID
2,OrderLine
1,FulfillmentQuantity
5 -
FulfillmentDate
2019 年 2 月 2 日,FulfillmentID
52,OrderID
1,OrderLine
1,FulfillmentQuantity
3 -
FulfillmentDate
2019 年 1 月 1 日,FulfillmentID
53,OrderID
1,OrderLine
2,FulfillmentQuantity
10
-
讓我們看看查詢模型時會發生什麼事。 以下是一個表格視覺化比較,顯示 Order
表格 OrderID
數據欄的訂單和履行數量。
圖像呈現精確的結果。 不過,由於您只能依 Order
數據表 OrderID
數據列來篩選或分組,因此模型的實用性受到限制。
建立多對多事實指引的關聯
一般而言,我們不建議您使用多對多的基數來直接關聯兩個事實資料表。 主要原因是模型無法在報表視覺的篩選或分組方式上提供彈性。 在此範例中,視覺化圖表只能依 Order
表格的 OrderID
欄來篩選或分組。 另一個原因與您的數據質量有關。 如果您的資料有完整性問題,某些數據列可能會在查詢時因為多對多關係和 有限關聯性而被省略。
建議您實作 星型架構 設計,而非直接連結事實數據表。 這表示您新增維度數據表。 然後,這些維度數據表會使用一對多的關係來關聯事實數據表。 此設計方法很健全,因為它有效率地提供彈性的報告選項。 它可讓您使用任何維度數據表數據行來篩選或分組,以及摘要任何相關事實數據表的數據行。
讓我們考慮一個更好的解決方案。
請注意下列設計變更:
- 模型現在有四個額外的數據表:
OrderLine
、OrderDate
、Product
和FulfillmentDate
。 - 四個額外的資料表都是維度表,它們與事實表之間存在一對多的關聯性。
-
OrderLine
資料表包含OrderLineID
欄,其中儲存OrderID
值乘以 100,再加上OrderLine
欄位值,即為每個訂單行的識別碼。 -
Order
和Fulfillment
資料表現在各包含一個OrderLineID
數據列,而且不再包含OrderID
和OrderLine
數據列。 -
Fulfillment
數據表現在包含OrderDate
和ProductID
數據列。 -
FulfillmentDate
表僅與Fulfillment
表存在關聯。 - 所有識別碼欄位已隱藏。
花時間採用星型架構設計可提供下列優點:
- 報表視覺效果可以透過維度數據表中的任何可見數據行,篩選或群組。
- 報表視覺效果可以 摘要 事實數據表中的任何可見欄位。
- 套用至
OrderLine
、OrderDate
或Product
數據表的篩選會傳播至這兩個事實數據表。 - 所有關係都是一對多,每個關係均為中的
一般關係。 不會遮罩數據完整性問題。 如需關聯性評估的詳細資訊,請參閱 Power BI Desktop 中的模型關聯性。
建立較高粒紋事實的關聯
此多對多案例與本文所述的其他兩個案例非常不同。
讓我們考慮一個包含四個資料表的範例:Date
、Sales
、Product
和 Target
。
Date
和 Product
數據表是維度數據表,而一對多關聯性則與 Sales
事實數據表相關。 到目前為止,它代表良好的星型架構設計。 不過,Target
數據表尚未與其他數據表相關。
Target
資料表包含三個資料行:Category
、TargetQuantity
和 TargetYear
。 數據表的數據行揭示了年份和產品類別的粒度。 換句話說,每個產品類別每年都會設定用來測量銷售績效的目標。
因為 Target
數據表會將數據儲存在高於維度數據表的層級,因此無法建立一對多關聯性。 嗯,只有其中一種關係是真的。 讓我們來探索 Target
數據表如何與維度數據表相關。
建立較高粒度時間區間的關聯性
Date
與 Target
數據表之間的關係應該是一對多的關係。 這是因為 TargetYear
欄位值是日期。 在此範例中,每個 TargetYear
數據行都會儲存目標年份的第一個日期。
提示
當把事實儲存於比日期更細的時間粒度時,請將欄位的數據類型設為 Date (若使用日期索引鍵,則設為 整數)。 在數據行中,儲存代表時間週期第一天的值。 例如,年份期間會記錄為年份的 1 月 1 日,而月份期間會記錄為該月的第一天。
不過,必須小心,以確保月份或日期層級篩選會產生有意義的結果。 如果沒有任何特殊的計算邏輯,報表視覺效果可能會顯示目標日期確實是每年的第一天。 除了一月份之外,其他所有天和月份的目標數量都會匯總為空白。
下列矩陣視覺效果顯示報表使用者從一年向下切入到其月份時會發生什麼情況。 圖表彙總 TargetQuantity
欄。 (針對矩陣列已啟用顯示無數據項目 選項。)
若要避免此行為,建議您使用量值來控制事實數據的摘要。 控制摘要的其中一個方法是在查詢較低層級的時間區段時返回BLANK。 另一種方法是,使用一些複雜的 DAX,將數值分配至較低層級的時間段。
請考慮下列使用 ISFILTERED DAX 函式的量值定義。 它只會在未篩選 Date
和 Month
數據行時傳回值。
Target Quantity =
IF(
NOT ISFILTERED('Date'[Date])
&& NOT ISFILTERED('Date'[Month]),
SUM(Target[TargetQuantity])
)
下列矩陣視覺化會使用 Target Quantity
量值。 它會顯示所有每月目標數量都是空白的。
關聯較高的粒紋 (非日期)
將維度數據表中的非日期數據行關聯到事實數據表時,需要不同的設計方法(而且其粒紋高於維度數據表)。
Category
資料行(來自 Product
和 Target
數據表)包含重複的值。 因此,一對多關係中沒有單一的一方。 在此情況下,您必須建立多對多關係。 關聯性應該以單一方向傳遞篩選,從維度表傳遞到事實表。
現在讓我們看看表格的行。
在 Target
數據表中,有四個數據列:每個目標年份有兩個數據列(2019 年和 2020 年),以及兩個類別(服裝和配件)。 在 Product
數據表中,有三個產品。 兩個屬於服裝類別,一個屬於配件類別。 其中一種服裝色彩是綠色,其餘兩種是藍色。
在 Product
表中的 Category
欄進行的視覺群組化會產生如下結果。 不過,此圖像會產生正確的結果。 現在,我們來考慮 Product
資料表中的 Color
欄用來分組目標數量時會發生什麼事。
視覺效果會產生數據的歪曲。 這裏發生了什麼事?
Product
數據表中 Color
數據行的篩選會產生兩個數據列。 其中一個數據列適用於 [服裝] 類別,另一個則用於 [配件] 類別。 這兩個類別值會作為篩選器傳遞到 Target
表格。 換句話說,因為來自兩個類別的產品會使用藍色,這些類別 用來篩選目標。
若要避免此行為,如先前所述,建議您使用量值來控制事實數據的摘要。
請考慮下列量值定義。 請注意,類別層級底下的所有 Product
數據表數據行都會測試篩選條件。
Target Quantity =
IF(
NOT ISFILTERED('Product'[ProductID])
&& NOT ISFILTERED('Product'[Product])
&& NOT ISFILTERED('Product'[Color]),
SUM(Target[TargetQuantity])
)
下表視覺效果使用 Target Quantity
量值。 它會顯示所有色彩目標數量為空。
最終的模型設計如下所示。
關聯更高層次的事實指導
當您需要將維度數據表關聯至事實數據表,而事實數據表以比維度數據表更高的粒度儲存資料列時,請遵循下列指引:
-
針對較高等級的穀物資料日期
- 在事實數據表中,儲存時間週期的第一個日期。
- 建立日期數據表與事實數據表之間的一對多關聯性。
-
更多關於穀物的資訊
- 建立維度數據表與事實數據表之間的多對多關聯性。
-
針對這兩種類型
- 使用度量邏輯控制摘要—當使用較低階層的維度欄進行篩選或分組時,會傳回 BLANK。
- 隱藏可摘要的事實數據表數據行,以確保只能使用量值來摘要事實數據表。
相關內容
如需本文的詳細資訊,請參閱下列資源:
- 在 Power BI Desktop 中
模型關聯性 - 瞭解星型架構和Power BI 的重要性
- 關係疑難解答指引
- 問題? 嘗試詢問網狀架構社群
- 建議? 提供想法改善 Fabric