はじめに
はじめまして。ATLのヴィリアスです。
Power BI初心者の私が、DAXのCount系関数で悩みまくり、
Microsoft Docsを読んでもよく分からなかったため、色々検証してみました。
備忘録として、私が学んだことをここに残します。
※この記事は、Power BIでの動作がメインです。
※免責事項(必ず、ご一読ください)
本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
また、誤情報が入り込んだり、情報が古くなったりすることもありますので、
必ずしも正確性を保証するものではありません。ご了承ください。
検証に使うテーブル
Count系関数の検証にあたって、次の2つのテーブルをExcelで用意しました。
テーブル名: 各社の在庫
| 会社 | 製品 | 在庫数 |
|---|---|---|
| 〇〇社 | マウス | 1 |
| 〇〇社 | モニター | 3 |
| ✕✕社 | マウス | 10 |
| ○✕社 | (空文字) | 1 |
| △△社 | キーボード | 3 |
| △△社 | ヘッドホン | |
| □□社 | 0 | |
| □□社 | マウス | 3000 |
| □□社 | モニター |
テーブル名: ブール
| No | ブール値 |
|---|---|
| 1 | True |
| 2 | False |
| 3 | False |
| 4 | True |
| 5 | True |
Count系関数の一覧
まず最初に、Count系関数は8種類あります。
| 関数 | 説明 |
|---|---|
| Count |
値 (数値, 日付, 文字列) が入っている行数をカウント。 空文字もカウントする。 空白はカウントしない。 ブール値はカウントできない。 実はCountXの簡易版。 |
| CountA |
Count All 空白ではない行数をすべてカウント。 空文字、ブール値もカウントする。 |
| CountX |
Count Expression Countの色々できる版。 値 (数値, 日付, 文字列) が入っている行数をカウント。 第1引数にテーブルを取る。(フィルターしたテーブルなどを使うのが基本) 第2引数に式(列)を取る。 空白はカウントしない。 ブール値はカウントできない。 |
| CountAX |
Count All Expression CountAとCountXが合体したもの。 |
| CountRows | テーブルの行数を数える。空白もカウント。 |
| CountBlank | 列の空白をカウント。空文字もカウント。 |
| DistinctCount | 重複した値は加算せずにカウント。 空白と空文字は別としてカウント。 |
| DistinctCountNoBlank | 重複した値は加算せずにカウント。 空白はカウントしない。 空文字はカウント。 |
Count, CountA, CountX, CountAX の4つの違いが理解できれば、もう何も怖くないです。
では、それぞれ見ていきましょう。
Count
基本中の基本、Countです。
これは、 値 (数値, 日付, 文字列(空文字も含む)) をカウントします。
空白はカウントしません。
また、ブール値に対してCountを使うとエラーになります。
まず [在庫数] をカウントしたい場合は、次のように記述します。
/* COUNT(<列>) */
Count = COUNT('各社の在庫'[在庫数])
結果

全9行のうち、空白はカウントせずに在庫数が記入されている 7行 をしっかりカウントできていますね。
では次に 空文字がカウントされるか、[製品] で確認します。
Count = COUNT('各社の在庫'[製品])
結果

○✕社の [製品] は空文字ですが、しっかりカウントされて結果は 8 になりました。
では、ブール値にCountを使うとどうなるのか。

エラーが出ます。
以下、エラーメッセージの一部です。
メジャー 'ブール'[Count] での計算エラー: 関数 COUNT は、数値または日付に評価される引数を受け取ります。型 Boolean の値は操作できません。
「ブール値をカウントしたいよ!」という場合は、次のCountAを使います。
CountA (Count All)
CountAは Count All です。すべて(All)をカウントします。
CountAは、Countとほぼ変わりません。(Power BIでは)
ただ先ほども言ったように、CountAは True や False のブール値をカウントすることができます。
/* COUNTA(<列>) */
CountA = COUNTA('ブール'[ブール値])
CountAの補足
ちなみに、Excelに絡めてCountとCountAの違いを厳密に言うと、
まずCountAは対象列のセルの型に、数値やら文字列やらが混ざっていても、何でもカウントできます。
一方でCountは数値のカウントがメインとなるため、文字列が混ざるとそれはカウントされません。
次のExcelのスクリーンショットを見てください。

C4 と D4 にはそれぞれ、CountとCountAを使って A2:A7 をカウントした値が入っています。
そして、 A2:A7 には「1, 2, 3, 6」の数値と「四, 五」の文字列が入っています。
Countは数値のカウントがメインであるため、「四, 五」の文字列はカウントしません。したがって結果は 4 となります。
CountAは何でもカウントするため、数値だろうが文字列だろうが関係ありません。結果は 6 です。
ではなぜ冒頭で私は、
CountAは、Countとほぼ変わりません。(Power BIでは)
と言ったのか。
それはPower BIでは、列の型は1つに決定されるからです。
Excelでは、列の各セルに対して任意の型を設定できます。(例: A列の1行目の型は文字列、2行目は数値、3行目は文字列)
しかし、Power BIではそれができないのです。
1列目の型を数値とすれば1列目の全行の型が数値になりますし、文字列とすれば文字列になります。
つまりPower BIでは1列の中に色々な型が存在することがないため、
ブール値を除けばCountAもCountも同じように値をカウントできます。
そのため、「CountAとCountはほぼ変わらない」としています。
CountX (Count Expression)
CountXは Count Expression です。式(Expression)を使ってカウントします。
CountXは、第1引数にテーブルを、第2引数に式(というか列)を取ります。
例えば、'各社の在庫' テーブルの [在庫数] をカウントする場合、次のように記述します。
/* COUNTX(<テーブル>, <式>) */
CountX = COUNTX('各社の在庫', '各社の在庫'[在庫数])
この結果、ついさっき見た覚えがありませんか?
実はこれ、Countで [在庫数] をカウントしているのと変わらないんですよね。
「じゃあ、Countでいいじゃん。なんでCountXが存在するの?」
その答えはCountXの 第1引数は、FILTERなどで加工したテーブルを取ることができるからです。
例えば「'各社の在庫' テーブルの中で、在庫数が10以上の製品をカウントしたいよ!」というときは、次のように記述します。
CountX = COUNTX(FILTER('各社の在庫', '各社の在庫'[在庫数]>=10), '各社の在庫'[製品])
結果

第1引数で**「在庫数が10以上」にフィルターされるテーブルを取っています。
そして「在庫数が10以上」なのは、✕✕社のマウスと□□社のマウスであるため、結果は 2 となります。
このようにCountXは、Countよりも高度なカウントができます。**
もちろんCountと同様、空文字もカウントできます。
CountX = COUNTX(FILTER('各社の在庫', '各社の在庫'[在庫数]==1), '各社の在庫'[製品])
結果

○✕社の [製品] は空文字ですが、カウントできています。
CountAX (Count All Expression)
CountAXは Count All Expression です。すべて(All)を式(Expression)を使ってカウントします。
CountAXは、CountAとCountXが合体したものです。
そのため、第1引数にフィルター済みテーブルを取ったり、ブール値をカウントしたりすることができます。
/* COUNTAX(<テーブル>, <式>) */
CountAX = COUNTAX(FILTER('ブール', 'ブール'[No]<=3), 'ブール'[ブール値])
結果

ここでは「Noが3以下」にフィルターしているため、結果は 3 となります。
その他についてはCountAとCountXで説明しているので省略します。
CountRows
CountRowsはテーブルの行数(Rows)をカウントします。
/* COUTROWS([<テーブル>]) */
CountRows = COUNTROWS('各社の在庫')
簡単ですね!
また、引数が空でも大丈夫です。
その場合、メジャーが存在するテーブル(ホームテーブル)の行数がカウントされます。
CountRows = COUNTROWS()
このように、メジャーCountRowsは 'ブール' テーブル下にあるため、引数をなしにすると 'ブール' テーブルの行数 5 を取得できます。
CountBlank
CountBlankは空白(Blank)をカウントします。空文字もカウントします。
/* COUNTBLANK(<列>) */
CountBlank = COUNTBLANK('各社の在庫'[製品])
結果

○✕社の空文字も、□□社の空白もカウントし、結果は 2 になりました。
DistinctCount
DistinctCountは重複する値を加算せず(Distinct)にカウントします。
空白と空文字は 別物 としてカウントされます。
/* DISTINCTCOUNT(<列>) */
DistinctCount = DISTINCTCOUNT('各社の在庫'[製品])
結果

[製品] には「マウス, モニター, キーボード, ヘッドホン」の4つに加えて、空文字と空白の2つがあります。
したがって、結果は 6 となります。
重複する値が1つとしてカウントされているのが分かりますね。
DistinctCountNoBlank
DistinctCountNoBlankはDistinctCountが空白を無視(NoBlank)するようにしたものです。
空文字は無視されません。
/* DISTINCTCOUNTNOBLANK(<列>)*/
DistinctCountNoBlank = DISTINCTCOUNTNOBLANK('各社の在庫'[製品])
結果

DistinctCountでは 6 でしたが、DistinctCountNoBlankは□□社の空白を無視するため 5 となります。
また、○✕社の空文字は無視されていないのも確認できます。
おわりに
自分なりにCount系関数をまとめてみましたが、いかがだったでしょうか。
この記事が、私と同じように悩んでいる方の助けになれば幸いです。
それではまた、次の記事で。




