【PowerBI】共通ディメンションがないファクトテーブル同士を結合する方法

【PowerBI】共通ディメンションがないファクトテーブル同士を結合する方法

こんにちはMJです!

マイクロソフトでは、データモデルを作成する際にスター スキーマがよく強調されています。

スター スキーマとは、一意識別子の役割を持つディメンションテーブルと、実際のデータを保存するファクトテーブルで構成されるモデリング技術です。

詳細についてはマイクロソフトのドキュメントをご確認ください。 スター スキーマと Power BI での重要性を理解する

 

複数のFactテーブルを接続して同時に分析したいものの、共通のディメンションテーブルが存在しない状況に直面することがあります。

この記事では、Power BIで2つのファクトテーブルを接続するための共通ディメンションテーブルを簡単に作成する方法を紹介します。

 

なぜファクトテーブル同士を直接接続してはいけないのか?

データモデルを作成する際、ファクトテーブル同士を直接【多対多】で接続することは推奨されていません。その理由としては以下となります。

1.重複計算や誤った集計が発生する可能性があるファクトテーブルは基本的に、同じ日付、同じ項目が重複して保存されているテーブルです。

このような2つのテーブルを接続すると、片方の行がもう片方の複数行とマッチし、実際よりも数倍多く計算されてしまう現象が発生します。

 

2.拡張性が低下する2つのテーブルを直接接続すると、後から新しいディメンションや属性を追加しにくくなり、データモデルの再利用性が低下します。

 

3.レポートのフィルタリングができない1つのスライサーで複数のビジュアルを同時に制御したい場合、共通のディメンションテーブルがなければフィルタリングが正しく動作しません。

 

サンプルデータ

今回は次の2つのファクトテーブルを使用します。

1.マーケティング費用データキャンペーンと広告チャネルごとに、日付別の表示回数、クリック数、広告費用のデータを保存しています。

配信日、キャンペーン名、広告チャネルの値が各列内で重複しています。

 

2.売上データキャンペーンと商品カテゴリごとに、日付別の注文数と売上金額のデータを保存しています。

注文日、キャンペーン名、商品カテゴリの値が各列内で重複しています。

日付データとキャンペーンに関するデータは、それぞれディメンションテーブルを作成できそうです。

それでは、DAXでディメンションテーブルを作成し、共通の軸として可視化してみましょう。

 

カレンダーテーブルの作成

正しい時系列ビジュアルを表現するため、すべてのファクトテーブルから日付データを抽出し、存在する最小/最大日付範囲を基準に共通の日付ディメンションテーブルを作成します。

DAX実装

Dim_Calendar = 
VAR MinDate =
    MIN(
        MIN('Factマーケ費用'[配信日]),
        MIN('Fact売上'[注文日])
    )

VAR MaxDate =
    MAX(
        MAX('Factマーケ費用'[配信日]),
        MAX('Fact売上'[注文日])
    )

RETURN
CALENDAR(MinDate, MaxDate)

DAXのMIN、MAX関数で2つのテーブルそれぞれの最小・最大日付を取得した後、CALENDAR関数を使って全体範囲のカレンダーテーブルを簡単に作成できます。

 

追加の列が必要な場合は、「新しい列」を使用して必要な列を作成することも可能です。

 

PowerQuery実装

let
    MarketingMin = List.Min(#"Factマーケ費用"[配信日]),
    MarketingMax = List.Max(#"Factマーケ費用"[配信日]),

    SalesMin = List.Min(#"Fact売上"[注文日]),
    SalesMax = List.Max(#"Fact売上"[注文日]),

    MinDate = List.Min({MarketingMin, SalesMin}),
    MaxDate = List.Max({MarketingMax, SalesMax}),

    DateList =
        List.Dates(
            MinDate,
            Duration.Days(MaxDate - MinDate) + 1,
            #duration(1,0,0,0)
        ),

    CalendarTable =
        Table.FromList(DateList, Splitter.SplitByNothing(), {"Date"}),

    ChangedType =
        Table.TransformColumnTypes(CalendarTable, {{"Date", type date}})

in
    ChangedType

各日付カラムをリスト形式で取得し、全体範囲を計算した後、テーブル形式に変換することでカレンダーテーブルを作成できます。

 

大容量データ環境や、データ更新パフォーマンスが重要な環境では、PowerQueryでカレンダーテーブルを作成する方が有利な場合があります。

列を追加したい場合は、Table.AddColumn()関数を使用してデータを追加できます。

 

共通ディメンションテーブルの作成

スライサーを統合し、正確な集計を行うために、もう1つの共通ディメンションであるキャンペーンディメンションを作成してみましょう。

DAX実装

Dim_Campaign = 
DISTINCT(
    UNION(
        SELECTCOLUMNS(
            'Factマーケ費用',
            "Campaign Name", [キャンペーン名]
        ),
        SELECTCOLUMNS(
            'Fact売上',
            "Campaign Name", [キャンペーン名]
        )
    )
)

UNION関数とSELECTCOLUMNS関数を活用して、テーブルから必要なカラムのみを抽出し、1つのリストとして結合します。

その後、DISTINCT関数で重複を削除すれば、1つのディメンションテーブルが完成できます。

 

リレーション設定

先ほど作成した共通ディメンションテーブルを使って各ファクトテーブルと【1対多】関係で接続します。

 

スライサーテスト

レポート全体が共通のカレンダーテーブルの値によって正しくフィルタリングされていることを確認できます。

また、キャンペーンの凡例を通じて、各ファクトテーブルの値をフィルタリングすることもできます。

 

 

まとめ

「共通の軸がない」という問題は、Power BIのモデリングにおいて避けては通れない課題です。

複数のファクトテーブルを使用するPower BIモデルにおいて、共通の軸として使用するディメンションテーブルが存在しない場合は、PowerQueryやDAXでテーブルを作成してみてはいかがでしょうか?

 

BI製品のサポートはぜひKCMEで!

自然言語を使って簡単にデータの可視化ができるBIツール、ThoughtSpotの詳細はこちら

おすすめの記事