テクテク日記

テクテク=テクノロジー&一歩ずつ(テクテク)

Power BIによるSaaS分析4 -DAXによる指標構築②

前回(客数ベース指標)の続きですが、今回は収益ベース指標について紹介していきます。前回と同じく、めちゃくちゃ長い記事になりました。最後まで読めた人は是非、Power BI勉強会のDAX Bootcamp(定期開催)への参加をご検討下さい。

Demo file Download
https://bit.ly/3507aj8

Tabular Editor 3を持っている方でとにかくメジャーだけ取得したいという方は一番下の「DAXスクリプト」へ飛んでコードを全てコピーしてTE3のDAX Scriptに張り付けて実行をしてください(詳細は「DAXスクリプト」をご参照)。
TE2とTE3の違い

DAXで定義する収益指標

  • 月次経常収益(Total MRR - Monthly Recurring Revenue)
Total MRR =
CALCULATE ( SUM ( Sales[MonthlyPrice] ), Sales[MonthlyPrice] > 0 )
//MRR = Monthly Recurring Revenue。通常の売上高に相当
//この式を使用する
Total MRR_beta = SUM ( Sales[MonthlyPrice] )

MRRは月次課金のSaaSビジネスで最も重要な指標で、他のビジネスでいうところの月次売上高に相当します。上記より、メジャーは[Total MRR]と[Total MRR_beta]の2つを作りましたが、結果は下図の通りです。

① Total MRR vs ② Total MRR_beta

f:id:marshal115:20220218155708p:plain

結果は同じですが、①は2021年2月が空白、②は0として計算されており、後者はトライアル顧客のデータを含む結果となりました。どちらも正しい結果ですが、MRRについては有料顧客(Signup顧客)の数字を見たいので、②ではなく、①の結果を出す(2021年1月と2月を非表示する)ために、CALCULATEを使って、Sales[MonthlyPrice]で値が0となっている項目をSUMで評価する前に除外しています。

なお、DAXに関する細かい話になりますが、dPricing[MonthlyPrice]とSales[MonthlyPrice]は1-多の関係にありますので、上記式を以下のように書き換えることもできます。

Total MRR =
CALCULATE ( SUM ( Sales[MonthlyPrice] ), dPricing[MonthlyPrice] > 0 )
//MRR = リレーションシップを使ったTotal MRRの計算
//この式は使用しない

この場合、Sales[MonthlyPrice]ではなく、dPricing[MonthlyPrice]でフィルターしているので結果は同じになりますが、dPricing[MonthlyPrice]列でフィルターを行うと、結果が全て同じ(全ての合計値)になってしまいます(下図)。

f:id:marshal115:20220218160720p:plain

DAXの基礎を学んだ人であれば上記式がSyntax Sugar(糖衣構文)であり、実際にはCALCULATEのフィルター引数は下記のように書き換えられていることを知っています。

Total MRR = 
CALCULATE (
    SUM ( Sales[MonthlyPrice] ),
    FILTER (
        ALL ( dPricing[MonthlyPrice] ),
        dPricing[MonthlyPrice] > 0
    )
)
//この式は使用しない
//ALLはフィルターを無視する機能の関数であるため、dPricing[MonthlyPrice]の
//フィルターに関係なく、合計値がMonhtlyPriceの結果として集計されている

このDAXの動作はDAXを学び始めた人がクリアすべき最初の難関であり、詳細は下記SQLBIを見て頂くと分かりやすい(英語ですが、翻訳機能で対応を)。

なお、一番最初の式(①)と同じ結果を得るために、KEEPFILERSを使った書き方で対応できます。

Total MRR =
CALCULATE (
    SUM ( Sales[MonthlyPrice] ),
    KEEPFILTERS ( dPricing[MonthlyPrice] > 0 )
)
//MRR = リレーションシップを使ったTotal MRRの計算
//KEEPFILTERSを使うことで、列がALLによってオーバーラードされるのを防ぐ
//この式を使用してもOK
CALCULATE (
    SUM ( Sales[MonthlyPrice] ),
    KEEPFILTERS (
        FILTER ( 
        ALL ( dPricing[MonthlyPrice] )
        dPricing[MonthlyPrice] > 0 )
    )
)

上記2つの式がこれに当たりますが、上の式(ALLがないほう)がSyntax Sugar、下(ALLがあるほう)が計算エンジンによる内部処理の構文となっています。どちらも結果は同じですが、下図のようになります。

f:id:marshal115:20220218162421p:plain

このTotal MRRをベースに、他の収益ベース指標を構築していきます。

  • 前月MRR(Total MRR.PM)
Total MRR.PM =
CALCULATE ( [Total MRR], DATEADD ( dCalendar[Date], -1, MONTH ) )
//前月MRR

客数指標の時と同じように、前月のMRRは非常に大事なので、DATEADD関数で計算しておきます。

  • StandardプランのみMRR(StandardOnly MRR)
StandardOnly MRR =
//全てのプランがStandardプランと想定した場合のMRR
VAR _price = 1090
VAR _result =
    IF (
        NOT ISBLANK ( [Total MRR] ),
        CALCULATE (
            SUMX ( Sales, _price ),
            KEEPFILTERS ( dEventType[EventType] = "Signed-up" )
        )
    )
RETURN
    _result

なにやら難しそうな計算式になりましたが、計算式が意味しているのは下図のPremiumプランである2,170円/月が仮に全てStandardプランの1,090円/月だった場合を想定したDAX式になっています。

f:id:marshal115:20220213171712p:plain

2,170円はPremiumプランですが、StarndardからPremiumへ切り替えた場合に増加するMRRがExpansion MRRと言われています(下図)。

f:id:marshal115:20220218165344p:plain

ExpansionはSaaS事業者にとって収益を拡大させるための有効な手段の1つであり、Power BIの世界で言えば、Power BI ProとPremium Per Userがこれに当たります。

通常、サービスのアップグレード・ダウングレードといった表現をしますが、

アップグレード: StandardからPremium(収益が拡大 = Expansion)

ダウングレード: PremiumからStandard(収益が縮小 = Contraction)

と覚えておくと良いと思います。なお、デモファイルは簡易化のため、アップグレードというシナリオしか想定していません。

客数ベースの指標とは異なり、収益ベースの指標はこのようにExpansionとContractionが混ざり合った結果の数字となりますので、指標に対する解釈が少し複雑になってきます。ただ、DAXによる指標構築のロジック自体は殆ど同じです。

ここで、少し話を戻して、上記[StandardOnly MRR]というメジャーですが、以下のように書き換えることも可能です。この場合、変数_priceがハードコーディングされた値(1,090)ではなく、StandardプランのPriceが変わった時に自動的に反映されるようになります。

StandardOnly MRR2 =
//全てのプランがStandardプランと想定した場合のMRR
VAR _price =
    CALCULATE (
        SELECTEDVALUE ( dPricing[MonthlyPrice] ),
        dPricing[PriceType] = "Standard",
        REMOVEFILTERS ()    //これがないと、dPricing[MonthlyPrice]で見た場合、間違った結果になる
    )
VAR _result =
    IF (
        NOT ISBLANK ( [Total MRR] ),
        CALCULATE (
            SUMX ( Sales, _price ),
            KEEPFILTERS ( dEventType[EventType] = "Signed-up" )
        )
    )
RETURN
    _result

ただし、上記DAXはREMOVEFILTERSALLといった関数を入れないと、dPricing[MonthlyPrice]で切ったときに、正しい値が算出されません。これはdPricing[PriceType]がSort列によって並び替え(列による並び替え)された場合に起こる現象です。

f:id:marshal115:20220218173944p:plain

理由はPower BIの仕様であり、列による並び替え(Sort by Column)が関係しています(詳しくは下記SQLBIの記事より)。

  • Expansion貢献分MRR(delta Expansion MRR)
delta Expansion MRR = [Total MRR] - [StandardOnly MRR]

Standard + Premiumプランの両方を含む[Total MRR]から[StandardOnly MRR]を差し引いてあげることで、時系列別にPremiumプランによる貢献度を測ることができるようになります。delta(増減)というネーミングはこれを意図したものですが、非常にセンスがないのは承知しています。

  • Expansion貢献分MRR比率(delta Expansion MRR vs Total MRR)
delta Expansion MRR vs Total MRR =
DIVIDE ( [delta Expansion MRR], [Total MRR] )
//Premiumによる増収額の全MRRに占める割合

全MRRに占めるPremiumによる貢献額を算出したのが上記の計算です。一方、下記のように、StandardプランとPremiumプランのMRRを別々に計算してみます。

  • StandardプランMRR(MRR by Standard)
MRR by Standard =
CALCULATE ( [Total MRR], KEEPFILTERS ( dPricing[PriceType] = "Standard" ) )
//StandardプランによるMRR
  • PremiumプランMRR(MRR by Premium)
MRR by Premium =
CALCULATE ( [Total MRR], KEEPFILTERS ( dPricing[PriceType] = "Premium" ) )
//PremiumプランによるMRR

上記メジャーをまとめたのが下表です。

f:id:marshal115:20220219205037p:plain

ここで混乱しやいのが④と⑦のメジャーの違いでしょうか。この2つのメジャーの違いを説明するために、1人の顧客だけでフィルターしてみます(CustomerID = mps_00007)。

f:id:marshal115:20220219205749p:plain

前述の通り、④はプランに関係なく、全て1,090円/月のStandardプランだと仮定した場合のMRRであり、⑦は当該顧客がStandardプランだった時のMRRとなります。そのため、2021年11月にPremiumへアップグレードしたことで⑦は空欄となり、⑧のPremiumプランに2,170円/月として登場しています。また、⑦と⑧の合計は①であり、①から④を差し引いたもの(⑤)が、Premium後の毎月の貢献額となります。

  • 新規顧客MRR(MRR from New Customers)
MRR from New Customers = 
//新規顧客によるMRR(新規顧客×単価)
CALCULATE(
    SUMX(
        Sales,
        var _current_price = Sales[MonthlyPrice]
        var _current_date = Sales[Date]
        var _first_signup_date = 
            CALCULATE(
                SELECTEDVALUE( dCustomer[StartDate] ),
                dEventType[EventType] = "Signed-up"
            )
        var _date_int = INT (_current_date = _first_signup_date )
        //1 = TRUE or 0 = FALSEになる。
        var _result = _current_price * _date_int   //1となっている行の単価と計算
        return _result
    ),
    Sales[MonthlyPrice] > 0
)
//ALLEXCEPTではなく、SELCTEDVALUEを使った書き方。クエリプランが改善される(SEクエリが減少する)

この指標は新規顧客によって増加したMRRであり、スタートアップの時はこの指標の伸びが重要視されるようです。

  • ネット新規MRR(Net MRR from New Customers)
Net MRR from New Customers = [Total MRR] - [Total MRR.PM]
//今月MRR - 前月MRR

上記ネット新規MRRの最もシンプルな計算式が「今月のMRRから前月のMRRを差し引く」ことですが、これは言い換えれば、新規顧客によるMRRと解約顧客によるネガティブMRR、更にExpansionやContractionを加味してネット(純額)のMRRであり、下式と同じ結果となります。

Net MRR from New Customers =
[MRR from New Customers] + [Expansion MRR] - [Contraction MRR] - [Churn MRR]

上記、[Expansion MRR]と[Contraction MRR]、[Churn MRR]の計算式はそれぞれ定義できますが、全てを1つのDAX式に収めようとすると非常に長くなってしまうので、計算に必要な以下の計算列をSalesテーブルに追加します。

ExpConFlag =
//こちらは計算列
VAR _current_prirce = Sales[MonthlyPrice]
VAR _previous_month =
    EDATE ( Sales[Date], -1 )
VAR _customer = Sales[CustomerID]
VAR _event_type = Sales[EventType]
VAR _price_shifted =
    //同じ顧客の前月のMonthlyPriceを抽出
    CALCULATE (
        MAX ( Sales[MonthlyPrice] ),
        FILTER ( Sales, Sales[Date] = _previous_month && Sales[CustomerID] = _customer ),
        Sales[EventType] = "Signed-up"
    )
VAR _new_date =
    CALCULATE (
        SELECTEDVALUE ( dCustomer[StartDate] ),
        dEventType[EventType] = "Signed-up"
    ) //初回サインアップした月を抽出
VAR _new_flag =
    IF ( Sales[Date] = _new_date, 1, BLANK () ) //初回サインアップした月を1とする
VAR _result =
    SWITCH (
        TRUE (),
        _new_flag = 1, BLANK (),
        //初回サインアップ月は除外
        _current_prirce > _price_shifted, "Upgrade",
        _current_prirce < _price_shifted, "Downgrade"
    )
RETURN
    _result

計算列(ExpConFlag)は各カスタマーにおけるUpgrade or Downgradeしたタイミングを取得するものです。計算列はデータモデルのサイズの肥大化やモデルの更新パフォーマンスの低下を招く原因になりますが、今回の場合、計算結果が3つ(Upgrage/Downgrad/空白)になりますので、特に問題ありません。

これでようやく、下記[Expansion MRR]と[Contraction MRR]が計算できるようになりました。

  • エクスパンションMRR(Expansion MRR)
Expansion MRR = 
//その月その時点のPremiumへアップグレードしたMRR(顧客別差額分)
SUMX (
    FILTER ( Sales, Sales[ExpConFlag] = "Upgrade" ),
    VAR _premium =
        CALCULATE (
            SELECTEDVALUE ( dPricing[MonthlyPrice] ),
            dPricing[PriceType] = "Premium",
            REMOVEFILTERS ()
        )
    VAR _standard =
        CALCULATE (
            SELECTEDVALUE ( dPricing[MonthlyPrice] ),
            dPricing[PriceType] = "Standard",
            REMOVEFILTERS ()
        )
    VAR _result = _premium - _standard
    RETURN
        _result
)

結果は以下のようになります。顧客ID「mps_00002」のExpansion MRRは

① = ② - ③

という式で計算され、今月のMRR(Premium)から前月のMRR(Standard)を差し引いた金額となって計算されているのが分かります。

f:id:marshal115:20220220162633p:plain

  • コントラクションMRR(Contraction MRR)
Contraction MRR = 
//その月その時点のStandardへダウングレードしたMRR(顧客別差額分)。
//デモではDowngradeがないため、全てゼロ

SUMX(
    FILTER( sales, Sales[ExpConFlag] = "Downgrade"),
    VAR _premium =
        CALCULATE (
            SELECTEDVALUE ( dPricing[MonthlyPrice] ),
            dPricing[PriceType] = "Premium",
            REMOVEFILTERS ()
        )
    VAR _standard =
        CALCULATE (
            SELECTEDVALUE ( dPricing[MonthlyPrice] ),
            dPricing[PriceType] = "Standard",
            REMOVEFILTERS ()
        )
    VAR _result =
        ABS ( _standard - _premium )
    RETURN
        _result
)

コントラクションはデモで想定していないため、全てゼロとなります。

  • チャーン(解約)MRR(Churn MRR)
Churn MRR = 
CALCULATE(
    SUMX(
        Sales,
        var _current_price = Sales[MonthlyPrice]
        var _current_date = Sales[Date]
        var _last_date = 
            CALCULATE(
                SELECTEDVALUE( dCustomer[EndDate] ),
                dEventType[EventType] = "Signed-up"
            )
        var _date_int = IF( _current_date = _last_date, 1, BLANK() )
        //1 = TRUE or 0 = FALSEになる。
        var _result = _current_price * _date_int   //1となっている行の単価と計算
        return _result
    ),
    DATEADD( dCalendar[Date], -1, MONTH )
)

チャーンMRRですが、下図の通りとなっています。

f:id:marshal115:20220220163311p:plain

ここで2021年8月の金額(3,260)をドリルダウンしてみると、下図のようになります。

f:id:marshal115:20220220163723p:plain

dCustomer(顧客マスタ)より、mps_00001とmps_00004はどちらも最終月が2021年7月であり、その翌月にチャーンMRRが計上されています。mps_00001はPremiumへUpgradeしているため、チャーンMRRは2,170円、mps_00004はUpgrageしていないため、従来のStandardプランの1,090円がチャーンMRRとなりました。これら2つの合計が同月の3,260円というチャーンMRRとなりました。

これにより、下記4つのメジャー同士を計算すると、ネット新規MRRが算出されます。

[Net MRR from New Customers 2] = [MRR from New Customers] + [Expansion MRR] - [Contraction MRR] - [Churn MRR]

下図は2つの方法から算出されたネット新規MRRで、どちらも結果が一致していることが分かります。

f:id:marshal115:20220220164756p:plain

複数のメジャーを基に計算されたこの指標は「今月MRR - 前月MRR」と同じですが、

ビジネスが成長把握しているかどうか

を見るための重要な指標(この場合、KPI*1)となります。ただし、重要なKPIではありますが、

どれだけ効果的に成長しているかはわからない

のがボトルネックとなります。単純化のため、MRRのExpansionやContractionがないものとし、Net MRRが毎月1ずつ成長しているSaaSビジネスがあるとします。

f:id:marshal115:20220220155643p:plain

この場合、確かに毎月継続的に成長していますが、顧客離反率(チャーンレート)が(直観的にも)高くなっているのが分かります。一方、同じ結果ではあるが、下図のように、新規顧客が少なくとも顧客チャーンが殆どない場合もあります。

f:id:marshal115:20220220160428p:plain

どちらもネット新規MRRは同じ増加額ですが、トップライン収益(MRR)だけでなく、新規顧客を獲得するために必要なコストを考えると、圧倒的に後者のほうが効率的に成長していることになります。

当たり前ですが、顧客チャーンが高い場合、サービスあるいは価格体系に対する不満、競合他社への乗り換え等が原因ですが、一度失った顧客を取り返すのは容易なことではないため、新規顧客獲得に対して投資を行うことになります(前者)。一方、顧客が満足してサービスを使い続ける限り、SaaS企業は既存顧客からフィードバックを受け取り、製品サービスの改善にリソースを費やすことができるわけです(後者)。

前者と後者を比較すると、数倍あるいは数十倍というコストの差が出てくると言われており、後者が健全なSaaSのビジネスモデル(ただし、スタートアップ初期に急速に新規顧客を増やせないと、将来性がないと見なされてしまう)になるというわけです。これが、上述した「効果的に成長しているかどうか」の話であり、

ネット新規MRR + 効果的な成長に関するKPI

の2つの判断基準が必要になってくるわけです。この「効果的な成長に関するKPI」ですが、いくつか考えられる指標がありますが、最も有名なのが売上維持率(NRR -Net Revenue Retention)となります。NRRは前回紹介した顧客リテンション率(Customer Retention)を売上ベースで計算した場合の指標で、以下のように定義されます。

  • 売上維持率 = NRR(Net Revenue Retention)
Net Revenue Retention =
DIVIDE ( [Total MRR] - [MRR from New Customers], [Total MRR.PM] )
//NRR = Net Revenue Retentionの略。ExpansionやContractionにより100%を超える時がある
//(先月MRR + Expansion MRR – Contraction MRR – Churn MRR ) ÷ 先月MRRと同じ
Net Revenue Retention2 =
DIVIDE (
    [Total MRR.PM] + [Expansion MRR] - [Contraction MRR] - [Churn MRR],
    [Total MRR.PM]
)
//NRR = Net Revenue Retentionの略。(今月MRR - 今月新規MRR) ÷ 前月MRRと同じ結果

定義は上記2つのどちらでも良く、[Net Revenue Retention2]のほうがより詳細な指標を利用しているため、両方を知っておくと良いでしょう。なお、客数ベースで算出される(前回参照)顧客リテンション率(Customer Retaintion Rate)はサービス・クオリティの把握に必要な指標で、大きいほど良いのですが、最大100%という数値になります。これら3つの指標を並べたものは以下の通り。

f:id:marshal115:20220220171345p:plain

ご覧の通り、[Customer Retention]と[Net Revenue Retention]は似たような数字となっていますが、後者のほうが100%を超えているケースが見受けられます。これは、料金プランをUpgradeした際のExpansion MRRが関係しており、例えば2021年10月を見ると、顧客リテンション率が100%から▲14%下落しているにも関わらず、売上維持率は100%のままで、トップラインには影響がなかった月となりました。

当然ながら、Donwgradeした場合の影響も大きく、SaaSビジネスを営む企業としては

ネット新規MRRを最大化させつつ、NRRも同時に観測していく

ことが重要となります。

最後に、クイックレシオというKPIを含むいくつかの指標を紹介して今回を終わりにしたいと思います。

  • グロス・レベニュー・チャーン(Gross Revenue Churn)
Gross Revenue Churn =
DIVIDE ( [Churn MRR], [Total MRR.PM] )
//当月チャーンMRR ÷ 前月チャーンMRR

当月の解約数やプラン変更などのダウングレードによって発生したMRRの減少分を、前月末時点でのMRRで除算して算出したものです。収益ベースの解約率(Dollar Churn Rate)とも言われ、顧客チャーン率と比較するとより実態に近い数値になります(下図)。

f:id:marshal115:20220220173022p:plain

  • ネット・レベニュー・チャーン(Net Revenue Churn)
Net Revenue Churn =
DIVIDE ( [Churn MRR] + [Contraction MRR] - [Expansion MRR], [Total MRR.PM] )
// (当月のChurn MRR + 当月のContraction MRR – 当月のExpansion MRR) ÷ 前月末のMRR

グロス・レベニュー・チャーンとの違いは、既存顧客の解約やダウングレードだけではなく、アップグレードなどによって発生した収益の増加も考慮している点にあります。従って、解約やダウングレードよりもアップグレードが上回った場合はマイナスの値になる特徴があります(下図)。

f:id:marshal115:20220220173819p:plain

  • クイック・レシオ(Quick Ratio)
Quick Ratio =
DIVIDE (
    [MRR from New Customers] + [Expansion MRR],
    [Churn MRR] + [Contraction MRR]
)
//(New MRR + Expansion MRR) ÷ (Churn MRR + Downgrade MRR)

クイック・レシオは「顧客ロイヤリティ」を担保できているかの判断であり、計算結果は以下の意味合いを持っているようです。

  • Quick Ratioが1未満の場合
    ビジネスが縮小中であり、将来性は極めて低い

  • Quick Ratioが1以上4未満の場合
    一見すると好調にも見えるが、顧客開拓が鈍化した途端に成長が止まるビジネスの可能性が高い。つまり、時間の経過(市場占有度の拡大)とともに、縮小へ向かうことが予想されるビジネス

  • Quick Ratioが4以上の場合
    効率的にビジネスが成長していると想定できる。「年間成長率が50%を超えるSaaS企業のQuick Ratioの平均値は4」というデータもある模様

f:id:marshal115:20220220174314p:plain

以上で全ての指標(計算列 + メジャー)の紹介が終わりましたが、非常に複雑な計算もあったかと思いますので、ご自身のペースに合わせて咀嚼をしてみてください。Tabular Editor 3(TE3)を使用できる方は、下記DAXスクリプトを前回と同じように使ってみてください。なお、計算列の追加は標準状態でサポートされていませんので、下図の手順①~②の通りに、サポートされていない項目に対する機能編集を有効にしてください。

f:id:marshal115:20220220174819p:plain

DAXスクリプト

使い方は前回からどうぞ。

問題なく、一気にメジャーを全て書き戻すためには、まずは上述した制限事項がない状態で、計算列を最初に追加してあげる必要があります(計算列の追加とメジャーの書き戻しを同時にやるとエラーが起こりますので、必ず「計算列を先に作る」こと)。

-----------------------------------------
-- Calculated Column: 'Sales'[ExpConFlag]
-----------------------------------------
COLUMN 'Sales'[ExpConFlag]
    //こちらは計算列
    VAR _current_prirce = Sales[MonthlyPrice]
    VAR _previous_month =
        EDATE ( Sales[Date], -1 )
    VAR _customer = Sales[CustomerID]
    VAR _event_type = Sales[EventType]
    VAR _price_shifted =
        //同じ顧客の前月のMonthlyPriceを抽出
        CALCULATE (
            MAX ( Sales[MonthlyPrice] ),
            FILTER ( Sales, Sales[Date] = _previous_month && Sales[CustomerID] = _customer ),
            Sales[EventType] = "Signed-up"
        )
    VAR _new_date =
        CALCULATE (
            SELECTEDVALUE ( dCustomer[StartDate] ),
            dEventType[EventType] = "Signed-up"
        ) //初回サインアップした月を抽出
    VAR _new_flag =
        IF ( Sales[Date] = _new_date, 1, BLANK () ) //初回サインアップした月を1とする
    VAR _result =
        SWITCH (
            TRUE (),
            _new_flag = 1, BLANK (),
            //初回サインアップ月は除外
            _current_prirce > _price_shifted, "Upgrade",
            _current_prirce < _price_shifted, "Downgrade"
        )
    RETURN
        _result
    Visible = FALSE

計算列が追加されたことを確認し、以下のスクリプトを全てコピペして実行してください。

-----------------------
-- Measure: [Total MRR]
-----------------------
MEASURE 'Sales'[Total MRR]
    CALCULATE ( SUM ( Sales[MonthlyPrice] ), Sales[MonthlyPrice] > 0 )
    //MRR = Monthly Recurring Revenue。通常の売上高に相当
    DisplayFolder = "MRR"
    FormatString = "#,0"

----------------------------
-- Measure: [Total MRR_beta]
----------------------------
MEASURE 'Sales'[Total MRR_beta] = SUM ( Sales[MonthlyPrice] )
    DisplayFolder = "MRR"
    FormatString = "#,0"

--------------------------
-- Measure: [Total MRR.PM]
--------------------------
MEASURE 'Sales'[Total MRR.PM]
    CALCULATE( [Total MRR], DATEADD( dCalendar[Date], -1, MONTH ) )
    //前月MRR
    DisplayFolder = "MRR"
    FormatString = "#,0"

------------------------------
-- Measure: [StandardOnly MRR]
------------------------------
MEASURE 'Sales'[StandardOnly MRR]
    //全てのプランがStandardプランと想定した場合のMRR
    VAR _price = 1090
    VAR _result =
        IF (
            NOT ISBLANK ( [Total MRR] ),
            CALCULATE (
                SUMX ( Sales, _price ),
                KEEPFILTERS ( dEventType[EventType] = "Signed-up" )
            )
        )
    RETURN
        _result
    DisplayFolder = "MRR"
    FormatString = "#,0"

-------------------------------
-- Measure: [StandardOnly MRR2]
-------------------------------
MEASURE 'Sales'[StandardOnly MRR2]
    //全てのプランがStandardプランと想定した場合のMRR
    VAR _price =
        CALCULATE (
            SELECTEDVALUE ( dPricing[MonthlyPrice] ),
            dPricing[PriceType] = "Standard",
            REMOVEFILTERS ()    //これがないと、dPricing[MonthlyPrice]で見た場合、間違った結果になる
        )
    VAR _result =
        IF (
            NOT ISBLANK ( [Total MRR] ),
            CALCULATE (
                SUMX ( Sales, _price ),
                KEEPFILTERS ( dEventType[EventType] = "Signed-up" )
            )
        )
    RETURN
        _result
    DisplayFolder = "MRR"
    FormatString = "#,0"

---------------------------------
-- Measure: [delta Expansion MRR]
---------------------------------
MEASURE 'Sales'[delta Expansion MRR]
    [Total MRR] - [StandardOnly MRR]
    //Premiumを含むMRRからStandardOnlyのMRRを減算したもの。Premiumによる増収額(Expansion)を算出
    DisplayFolder = "MRR"
    FormatString = "#,0"

----------------------------------------------
-- Measure: [delta Expansion MRR vs Total MRR]
----------------------------------------------
MEASURE 'Sales'[delta Expansion MRR vs Total MRR]
    DIVIDE([delta Expansion MRR], [Total MRR] )
    //Premiumによる増収額の全MRRに占める割合
    DisplayFolder = "MRR"
    FormatString = "0.0%;-0.0%;0.0%"

-----------------------------
-- Measure: [MRR by Standard]
-----------------------------
MEASURE 'Sales'[MRR by Standard]
    CALCULATE( [Total MRR], KEEPFILTERS( dPricing[PriceType] = "Standard" ) )
    //StandardプランによるMRR
    DisplayFolder = "MRR"
    FormatString = "#,0"

----------------------------
-- Measure: [MRR by Premium]
----------------------------
MEASURE 'Sales'[MRR by Premium]
    CALCULATE( [Total MRR], KEEPFILTERS( dPricing[PriceType] = "Premium" ) )
    //PremiumプランによるMRR
    DisplayFolder = "MRR"
    FormatString = "#,0"

------------------------------------
-- Measure: [MRR from New Customers]
------------------------------------
MEASURE 'Sales'[MRR from New Customers]
    //新規顧客によるMRR(新規顧客×単価)
    CALCULATE(
        SUMX(
            Sales,
            var _current_price = Sales[MonthlyPrice]
            var _current_date = Sales[Date]
            var _first_signup_date = 
                CALCULATE(
                    SELECTEDVALUE( dCustomer[StartDate] ),
                    dEventType[EventType] = "Signed-up"
                )
            var _date_int = INT (_current_date = _first_signup_date )
            //1 = TRUE or 0 = FALSEになる。
            var _result = _current_price * _date_int   //1となっている行の単価と計算
            return _result
        ),
        Sales[MonthlyPrice] > 0
    )
    //ALLEXCEPTではなく、SELCTEDVALUEを使った書き方。クエリプランが改善される(SEクエリが減少する)
    DisplayFolder = "MRR"
    FormatString = "#,0"

---------------------------
-- Measure: [Expansion MRR]
---------------------------
MEASURE 'Sales'[Expansion MRR]
    //その月その時点のPremiumへアップグレードしたMRR(顧客別差額分)
    SUMX (
        FILTER ( Sales, Sales[ExpConFlag] = "Upgrade" ),
        VAR _premium =
            CALCULATE (
                SELECTEDVALUE ( dPricing[MonthlyPrice] ),
                dPricing[PriceType] = "Premium",
                REMOVEFILTERS ()
            )
        VAR _standard =
            CALCULATE (
                SELECTEDVALUE ( dPricing[MonthlyPrice] ),
                dPricing[PriceType] = "Standard",
                REMOVEFILTERS ()
            )
        VAR _result = _premium - _standard
        RETURN
            _result
    )
    DisplayFolder = "MRR"
    FormatString = "#,0"

-----------------------------
-- Measure: [Contraction MRR]
-----------------------------
MEASURE 'Sales'[Contraction MRR]
    //その月その時点のStandardへダウングレードしたMRR(顧客別差額分)。デモではDowngradeがないため、全てゼロ
    SUMX(
        FILTER( sales, Sales[ExpConFlag] = "Downgrade"),
        VAR _premium =
            CALCULATE (
                SELECTEDVALUE ( dPricing[MonthlyPrice] ),
                dPricing[PriceType] = "Premium",
                REMOVEFILTERS ()
            )
        VAR _standard =
            CALCULATE (
                SELECTEDVALUE ( dPricing[MonthlyPrice] ),
                dPricing[PriceType] = "Standard",
                REMOVEFILTERS ()
            )
        VAR _result =
            ABS ( _standard - _premium )
        RETURN
            _result
    )
    DisplayFolder = "MRR"
    FormatString = "#,0"

----------------------------------------
-- Measure: [Net MRR from New Customers]
----------------------------------------
MEASURE 'Sales'[Net MRR from New Customers]
    [Total MRR] - [Total MRR.PM]
    //今月MRR - 前月MRR。MRR from New Customers + Expansion MRR - -Contaction MRR - Churn MRRと同じ
    DisplayFolder = "MRR"
    FormatString = "#,0"

-----------------------
-- Measure: [Churn MRR]
-----------------------
MEASURE 'Sales'[Churn MRR]
    CALCULATE(
        SUMX(
            Sales,
            var _current_price = Sales[MonthlyPrice]
            var _current_date = Sales[Date]
            var _last_date = 
                CALCULATE(
                    SELECTEDVALUE( dCustomer[EndDate] ),
                    dEventType[EventType] = "Signed-up"
                )
            var _date_int = IF( _current_date = _last_date, 1, BLANK() )
            //1 = TRUE or 0 = FALSEになる。
            var _result = _current_price * _date_int   //1となっている行の単価と計算
            return _result
        ),
        DATEADD( dCalendar[Date], -1, MONTH )
    )
    DisplayFolder = "MRR"
    FormatString = "#,0"

------------------------------------------
-- Measure: [Net MRR from New Customers 2]
------------------------------------------
MEASURE 'Sales'[Net MRR from New Customers 2]
    [MRR from New Customers] + [Expansion MRR] - [Contraction MRR] - [Churn MRR]
    //MRR from New Customers + Expansion MRR - -Contaction MRR - Churn MRR = 今月MRR - 前月MRRと同じ
    DisplayFolder = "MRR"
    FormatString = "#,0"

-----------------------------------
-- Measure: [Net Revenue Retention]
-----------------------------------
MEASURE 'Sales'[Net Revenue Retention]
    DIVIDE( [Total MRR] - [MRR from New Customers], [Total MRR.PM] )
    //NRR = Net Revenue Retentionの略。ExpansionやContractionにより100%を超える時がある
    //(先月MRR + Expansion MRR – Contraction MRR – Churn MRR ) ÷ 先月MRRと同じ
    DisplayFolder = "KPI"
    FormatString = "0.0%;-0.0%;0.0%"

------------------------------------
-- Measure: [Net Revenue Retention2]
------------------------------------
MEASURE 'Sales'[Net Revenue Retention2]
    DIVIDE( [Total MRR.PM] + [Expansion MRR] - [Contraction MRR] - [Churn MRR], [Total MRR.PM] )
    //NRR = Net Revenue Retentionの略。(今月MRR - 今月新規MRR) ÷ 前月MRRと同じ結果
    DisplayFolder = "KPI"
    FormatString = "0.0%;-0.0%;0.0%"

---------------------------------
-- Measure: [Gross Revenue Churn]
---------------------------------
MEASURE 'Sales'[Gross Revenue Churn]
    DIVIDE( [Churn MRR], [Total MRR.PM] )
    //当月チャーンMRR ÷ 前月チャーンMRR(グロスはExpansionやContraction等を全て加味しているため)
    DisplayFolder = "KPI"
    FormatString = "#,0.0%;-#,0.0%;#,0.0%"

-------------------------------
-- Measure: [Net Revenue Churn]
-------------------------------
MEASURE 'Sales'[Net Revenue Churn]
    DIVIDE( [Churn MRR] + [Contraction MRR] - [Expansion MRR], [Total MRR.PM] )
    // (当月のChurn MRR + 当月のContraction MRR – 当月のExpansion MRR) ÷ 前月末のMRR
    DisplayFolder = "KPI"
    FormatString = "0.0%;-0.0%;0.0%"

--------------------------
-- Measure: [Quick Ratio ]
--------------------------
MEASURE 'Sales'[Quick Ratio ]
    DIVIDE( [MRR from New Customers] + [Expansion MRR], [Churn MRR] + [Contraction MRR] )
    //(New MRR + Expansion MRR) ÷ (Churn MRR + Downgrade MRR)
    DisplayFolder = "KPI"

次回は下記より

marshal115.hatenablog.com

*1:Key Performance Indicatorの略