Salesforceで複数の条件の合致に対する組み合わせで結果を分けたい場合に使える数式をまとめておきます。
はじめに
複数の条件の合致に対する組み合わせによって、結果や処理を分けたいことがあるかと思います。
このとき、直感的にはIFによる条件分岐を使うことが多いのですが、組み合わせを網羅しようとすると冗長な数式になりやすく、数式のコンパイルの制限に係り易くなります。
この問題の発生を可能な限り減らすための数式の作り方を考えていきます。
本記事では 5つの選択肢を持つ複数選択リストの選択の組み合わせ を例として解説します。
組み合わせについて考える
前提として、何らかの条件は「満たすか満たさないか」の2通りのパターンを持ちます。
$N$個の条件に対しては、条件の組み合わせを$C$、条件分岐の数を$C_{\mathrm{if}}$として、
C = 2^{N} , C_{\mathrm{if}} = \sum_{i=0}^{N-1} 2^{i}
となり、条件数が多くなればなるほど 条件分岐の数が膨大な数になってしまう ことがわかります。
複数選択リストに5つの選択肢が存在し、選択の組み合わせによって結果を分ける場合は下記のような数式となります。
複数選択リストの選択の組み合わせを網羅する数式
IF(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢2,選択肢3,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢2,選択肢3,が選択されている場合の処理
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢2,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢2,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢2,が選択されている場合の処理
)
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢3,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢3,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢3,が選択されている場合の処理
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢1,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢1,選択肢5が選択されている場合の処理 ,
// 選択肢1,が選択されている場合の処理
)
)
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢2,選択肢3,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
// 選択肢2,選択肢3,が選択されている場合の処理
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢2,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢2,選択肢5が選択されている場合の処理 ,
// 選択肢2,が選択されている場合の処理
)
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢3,選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢3,選択肢5が選択されている場合の処理 ,
// 選択肢3,が選択されている場合の処理
)
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢4,選択肢5が選択されている場合の処理 ,
// 選択肢4が選択されている場合の処理
) ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢5が選択されている場合の処理 ,
// 何も選択されていない場合の処理
)
)
)
)
)
組み合わせの数で分岐する方法を考える
単純に複数の条件をAND条件で括ってしまえば、組み合わせの数と条件分岐の数を一致させることができます。
複数選択リストに5つの選択肢が存在し、選択の組み合わせを結合して結果を分ける場合は下記のような数式となります。
複数選択リストの選択の組み合わせを結合して網羅する数式
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢1,選択肢2,選択肢3,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" )
) ,
// 選択肢1,選択肢2,選択肢3が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢1,選択肢2,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢2,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢1,選択肢3,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢3,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢2,選択肢3,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢2" )
) ,
// 選択肢1,選択肢2が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢3" )
) ,
// 選択肢1,選択肢3が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢1,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢1,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢3" )
) ,
// 選択肢2,選択肢3が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢2,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢2,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢4" )
) ,
// 選択肢3,選択肢4が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢3,選択肢5が選択されている場合の処理 ,
IF(
AND(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
INCLUDES( 複数選択リスト , "選択肢5" )
) ,
// 選択肢4,選択肢5が選択されている場合の処理 ,
IF(
INCLUDES( 複数選択リスト , "選択肢1" ) ,
// 選択肢1が選択されている場合の処理 ,
IF(
INCLUDES( 複数選択リスト , "選択肢2" ) ,
// 選択肢2が選択されている場合の処理 ,
IF(
INCLUDES( 複数選択リスト , "選択肢3" ) ,
// 選択肢3が選択されている場合の処理 ,
IF(
INCLUDES( 複数選択リスト , "選択肢4" ) ,
// 選択肢4が選択されている場合の処理 ,
IF(
INCLUDES( 複数選択リスト , "選択肢5" ) ,
// 選択肢5が選択されている場合の処理 ,
// 何も選択されていない場合の処理
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
)
上記の例で分かる通り、単純に結合する方法では 単純に長くなるだけ になります。
しかし、長くなる原因を探ると 条件式が長い という点に着目できるかと思います。
条件式を短くする方法を考える
条件式が長くなる原因は至ってシンプルで、 IFの条件分岐は逐一条件を記述する必要がある という点にあります。
そのため、条件式を逐一記述しない方法を考えれば簡潔に記述できるようになると考えることができます。
CASEによる条件分岐の方法を採用する
CASEによる条件分岐は下記のような形式で記述するため、条件式を必要とするタイミングは1回限りになります。
CASE(
条件式 ,
評価値1 , 評価値1の処理 ,
評価値2 , 評価値2の処理 ,
評価値3 , 評価値3の処理 ,
...
評価値N , 評価値Nの処理 ,
デフォルトの処理
)
ただし、単に採用するだけでは 条件式をどのように作るか と 評価値をどのように設定するか という点に問題が生じます。
条件と評価に対してナンバリングを行うための準備
評価値は条件の組み合わせに該当するため、$N$個の条件に対して$C=2^{N}$個の評価値が存在します。
つまり、すべての条件の組み合わせに対する評価値のベクトル$V$は
V =
\begin{pmatrix}
0\\
1\\
2\\
\vdots\\
C-2\\
C-1
\end{pmatrix}
と表現することができます。
また、$N$個の選択肢に対する条件ベクトル$P$を
P =
\begin{pmatrix}
p_{0} = 1 \mathrm{.or.} 0 \\
p_{1} = 1 \mathrm{.or.} 0 \\
p_{2} = 1 \mathrm{.or.} 0 \\
\vdots\\
p_{N-2} = 1 \mathrm{.or.} 0 \\
p_{N-1} = 1 \mathrm{.or.} 0 \\
\end{pmatrix}
と定義します。ここで、$p_{i}=1$は 条件を満たしていること を示し、$p_{i}=0$は 条件を満たしていないこと を示しています。
さらに、$C$通りの条件ベクトルに対して行列$S$を、
S =
\begin{pmatrix}
P_{0}^\top & V_{0} に対する条件ベクトル \\
P_{1}^\top & V_{1} に対する条件ベクトル \\
P_{2}^\top & V_{2} に対する条件ベクトル \\
\vdots\\
P_{C-2}^\top & V_{C-2} に対する条件ベクトル \\
P_{C-1}^\top & V_{C-1} に対する条件ベクトル
\end{pmatrix}
と定義してみると、係数のベクトル$A$を用いて
SA = V
という関係式が成り立ちます。
ここで、係数のベクトル$A$は$N$個の要素を持っており、
A =
\begin{pmatrix}
2^{0} \\
2^{1} \\
2^{2} \\
\vdots\\
2^{N-2} \\
2^{N-1}
\end{pmatrix}
と表現されます。
$2^{N}-1$までの整数は$2^{n}(n=0,1,2,...,N-2,N-1)$の任意の$n$を重複なく選択した総和によって表すことができます。
条件と評価に対してナンバリングを行う
各条件に対して$A$の各要素を重複なく対応付け、条件ベクトルの行列$S$を作ることによって、対応する評価値のベクトル$V$を作ることができます。
複数選択リストに5つの選択肢に対して、
\begin{eqnarray}
選択肢1 &=& 2^{0} &=& 1 \\
選択肢2 &=& 2^{1} &=& 2 \\
選択肢3 &=& 2^{2} &=& 4 \\
選択肢4 &=& 2^{3} &=& 8 \\
選択肢5 &=& 2^{4} &=& 16
\end{eqnarray}
と設定すると、下記のような評価値のテーブルを作ることができます。
複数選択リストの選択の組み合わせと評価値のテーブル
$V$ | 選択肢1 | 選択肢2 | 選択肢3 | 選択肢4 | 選択肢5 | |
---|---|---|---|---|---|---|
0 | ||||||
1 | ○ | |||||
2 | ○ | |||||
3 | ○ | ○ | ||||
4 | ○ | |||||
5 | ○ | ○ | ||||
6 | ○ | ○ | ||||
7 | ○ | ○ | ○ | |||
8 | ○ | |||||
9 | ○ | ○ | ||||
10 | ○ | ○ | ||||
11 | ○ | ○ | ○ | |||
12 | ○ | ○ | ||||
13 | ○ | ○ | ○ | |||
14 | ○ | ○ | ○ | |||
15 | ○ | ○ | ○ | ○ | ||
16 | ○ | |||||
17 | ○ | ○ | ||||
18 | ○ | ○ | ||||
19 | ○ | ○ | ○ | |||
20 | ○ | ○ | ||||
21 | ○ | ○ | ○ | |||
22 | ○ | ○ | ○ | |||
23 | ○ | ○ | ○ | ○ | ||
24 | ○ | ○ | ||||
25 | ○ | ○ | ○ | |||
26 | ○ | ○ | ○ | |||
27 | ○ | ○ | ○ | ○ | ||
28 | ○ | ○ | ○ | |||
29 | ○ | ○ | ○ | ○ | ||
30 | ○ | ○ | ○ | ○ | ||
31 | ○ | ○ | ○ | ○ | ○ |
CASEによる条件分岐の方法で数式を作成する
条件の対応付けと評価値のベクトルが完成したことで、下記のような形式でCASEによる条件分岐を作ることができます。
CASE(
IF( 条件1 , 1 , 0 )
+ IF( 条件2 , 2 , 0 )
+ IF( 条件3 , 4 , 0 )
+ ...
+ IF( 条件N , 2^N , 0 ) ,
1 , 条件1のみ合致した場合の処理 ,
2 , 条件2のみ合致した場合の処理 ,
3 , 条件1と条件2が合致した場合の処理 ,
...
2^N-1 , すべての条件が合致した場合の処理 ,
すべての条件が合致しなかった場合の処理
)
前提となる数式の内容にも依存しますが、単純計算では約25%のコンパイルサイズの節約ができます。
複数選択リストに5つの選択肢が存在し、選択の組み合わせを結合して結果を分ける場合は下記のような数式となります。
複数選択リストの選択の組み合わせを結合して網羅する数式
CASE(
IF( INCLUDES( 複数選択リスト , "選択肢1" ) , 1 , 0 )
+ IF( INCLUDES( 複数選択リスト , "選択肢2" ) , 2 , 0 )
+ IF( INCLUDES( 複数選択リスト , "選択肢3" ) , 4 , 0 )
+ IF( INCLUDES( 複数選択リスト , "選択肢4" ) , 8 , 0 )
+ IF( INCLUDES( 複数選択リスト , "選択肢5" ) , 16 , 0 ) ,
1 , // 選択肢1が選択されている場合の処理 ,
2 , // 選択肢2が選択されている場合の処理 ,
3 , // 選択肢1,選択肢2が選択されている場合の処理 ,
4 , // 選択肢3が選択されている場合の処理 ,
5 , // 選択肢1,選択肢3が選択されている場合の処理 ,
6 , // 選択肢2,選択肢3が選択されている場合の処理 ,
7 , // 選択肢1,選択肢2,選択肢3が選択されている場合の処理 ,
8 , // 選択肢4が選択されている場合の処理 ,
9 , // 選択肢1,選択肢4が選択されている場合の処理 ,
10 , // 選択肢2,選択肢4が選択されている場合の処理 ,
11 , // 選択肢1,選択肢2,選択肢4が選択されている場合の処理 ,
12 , // 選択肢3,選択肢4が選択されている場合の処理 ,
13 , // 選択肢1,選択肢3,選択肢4が選択されている場合の処理 ,
14 , // 選択肢2,選択肢3,選択肢4が選択されている場合の処理 ,
15 , // 選択肢1,選択肢2,選択肢3,選択肢4が選択されている場合の処理 ,
16 , // 選択肢5が選択されている場合の処理 ,
17 , // 選択肢1,選択肢5が選択されている場合の処理 ,
18 , // 選択肢2,選択肢5が選択されている場合の処理 ,
19 , // 選択肢1,選択肢2,選択肢5が選択されている場合の処理 ,
20 , // 選択肢3,選択肢5が選択されている場合の処理 ,
21 , // 選択肢1,選択肢3,選択肢5が選択されている場合の処理 ,
22 , // 選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
23 , // 選択肢1,選択肢2,選択肢3,選択肢5が選択されている場合の処理 ,
24 , // 選択肢4,選択肢5が選択されている場合の処理 ,
25 , // 選択肢1,選択肢4,選択肢5が選択されている場合の処理 ,
26 , // 選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
27 , // 選択肢1,選択肢2,選択肢4,選択肢5が選択されている場合の処理 ,
28 , // 選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
29 , // 選択肢1,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
30 , // 選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
31 , // 選択肢1,選択肢2,選択肢3,選択肢4,選択肢5が選択されている場合の処理 ,
// 何も選択されていない場合の処理
)
まとめ
いくつもの条件を乱立した数式を作る場合はCASEが使えるように考え方を組み替えてやると、数式のサイズを減らしたりすることができます。
「$2^{N}-1$までの整数は$2^{n}(n=0,1,2,...,N-2,N-1)$の任意の$n$を重複なく選択した総和によって表すことができる」という点は他の場面でも役立つことがありそうなので、念頭に置いておきたいところです。