LoginSignup
13
7

More than 1 year has passed since last update.

DAXのCount系関数で混乱したのでまとめた

Last updated at Posted at 2021-10-28

はじめに

はじめまして。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を使うとエラーになります。

まず [在庫数] をカウントしたい場合は、次のように記述します。

DAX
/* COUNT(<列>) */

Count = COUNT('各社の在庫'[在庫数])

結果

全9行のうち、空白はカウントせずに在庫数が記入されている 7行 をしっかりカウントできていますね。

では次に 空文字がカウントされるか、[製品] で確認します。

DAX
Count = COUNT('各社の在庫'[製品])

結果

○✕社の [製品] は空文字ですが、しっかりカウントされて結果は 8 になりました。

では、ブール値Countを使うとどうなるのか。

エラーが出ます。

以下、エラーメッセージの一部です。

メジャー 'ブール'[Count] での計算エラー: 関数 COUNT は、数値または日付に評価される引数を受け取ります。型 Boolean の値は操作できません。

ブール値をカウントしたいよ!」という場合は、次のCountAを使います。

CountA (Count All)

CountACount All です。すべて(All)をカウントします。

CountAは、Countとほぼ変わりません。(Power BIでは)
ただ先ほども言ったように、CountATrue や False のブール値をカウントすることができます。

DAX
/* COUNTA(<列>) */

CountA = COUNTA('ブール'[ブール値])

結果

このように、ブール値がカウントできます。

CountAの補足

ちなみに、Excelに絡めてCountCountAの違いを厳密に言うと、
まずCountA対象列のセルの型に、数値やら文字列やらが混ざっていても、何でもカウントできます
一方でCountは数値のカウントがメインとなるため、文字列が混ざるとそれはカウントされません。

次のExcelのスクリーンショットを見てください。

C4 と D4 にはそれぞれ、CountCountAを使って 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列の中に色々な型が存在することがないため、
ブール値を除けばCountACountも同じように値をカウントできます。

そのため、「CountACountはほぼ変わらない」としています。

CountX (Count Expression)

CountXCount Expression です。式(Expression)を使ってカウントします。

CountXは、第1引数にテーブルを、第2引数に式(というか列)を取ります。
例えば、'各社の在庫' テーブルの [在庫数] をカウントする場合、次のように記述します。

DAX
/* COUNTX(<テーブル>, <式>) */

CountX = COUNTX('各社の在庫', '各社の在庫'[在庫数])

結果

結果は 7 になります。

この結果、ついさっき見た覚えがありませんか?
実はこれ、Countで [在庫数] をカウントしているのと変わらないんですよね。

「じゃあ、Countでいいじゃん。なんでCountXが存在するの?」
その答えはCountX第1引数は、FILTERなどで加工したテーブルを取ることができるからです。

例えば「'各社の在庫' テーブルの中で、在庫数が10以上の製品をカウントしたいよ!」というときは、次のように記述します。

DAX
CountX = COUNTX(FILTER('各社の在庫', '各社の在庫'[在庫数]>=10), '各社の在庫'[製品])

結果

第1引数で「在庫数が10以上」にフィルターされるテーブルを取っています。
そして「在庫数が10以上」なのは、✕✕社のマウス□□社のマウスであるため、結果は 2 となります。
このようにCountXは、Countよりも高度なカウントができます。

もちろんCountと同様、空文字もカウントできます。

DAX
CountX = COUNTX(FILTER('各社の在庫', '各社の在庫'[在庫数]==1), '各社の在庫'[製品])

結果

○✕社の [製品] は空文字ですが、カウントできています。

CountAX (Count All Expression)

CountAXCount All Expression です。すべて(All)を式(Expression)を使ってカウントします。

CountAXは、CountACountXが合体したものです。
そのため、第1引数にフィルター済みテーブルを取ったり、ブール値をカウントしたりすることができます。

DAX
/* COUNTAX(<テーブル>, <式>) */

CountAX = COUNTAX(FILTER('ブール', 'ブール'[No]<=3), 'ブール'[ブール値])

結果

ここでは「Noが3以下」にフィルターしているため、結果は 3 となります。

その他についてはCountACountXで説明しているので省略します。

CountRows

CountRowsテーブルの行数(Rows)をカウントします。

DAX
/* COUTROWS([<テーブル>]) */

CountRows = COUNTROWS('各社の在庫')

結果

簡単ですね!

また、引数が空でも大丈夫です。
その場合、メジャーが存在するテーブル(ホームテーブル)の行数がカウントされます。

DAX
CountRows = COUNTROWS()

結果

このように、メジャーCountRows'ブール' テーブル下にあるため、引数をなしにすると 'ブール' テーブルの行数 5 を取得できます。

CountBlank

CountBlank空白(Blank)をカウントします。空文字もカウントします。

DAX
/* COUNTBLANK(<列>) */

CountBlank = COUNTBLANK('各社の在庫'[製品])

結果

○✕社の空文字も、□□社の空白もカウントし、結果は 2 になりました。

DistinctCount

DistinctCount重複する値を加算せず(Distinct)にカウントします。
空白と空文字は 別物 としてカウントされます。

DAX
/* DISTINCTCOUNT(<列>) */

DistinctCount = DISTINCTCOUNT('各社の在庫'[製品])

結果

[製品] には「マウス, モニター, キーボード, ヘッドホン」の4つに加えて、空文字と空白の2つがあります。
したがって、結果は 6 となります。

重複する値が1つとしてカウントされているのが分かりますね。

DistinctCountNoBlank

DistinctCountNoBlankDistinctCount空白を無視(NoBlank)するようにしたものです。
空文字は無視されません。

DAX
/*  DISTINCTCOUNTNOBLANK(<列>)*/

DistinctCountNoBlank = DISTINCTCOUNTNOBLANK('各社の在庫'[製品])

結果

DistinctCountでは 6 でしたが、DistinctCountNoBlank□□社の空白を無視するため 5 となります。
また、○✕社の空文字は無視されていないのも確認できます。

おわりに

自分なりにCount系関数をまとめてみましたが、いかがだったでしょうか。
この記事が、私と同じように悩んでいる方の助けになれば幸いです。

それではまた、次の記事で。

参考にしたもの

13
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
7