Mark Hammer's blog

SalesforceやTrailheadに関する情報を投稿しているブログです。

Salesforce数式: エラーを返す数式を含むAND, ORの条件判定

はじめに

本投稿の元ネタは、こちらのブログです。

sf.forum.circlace.com

内容を簡単に書くと「項目から日付を持ってきて、その月に日曜日が何回あるかを算出する」とのことで、以下の数式が紹介されていました。

4
+ IF( AND( DAY(LastDay__c)>=29, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1), 1, 0)
+ IF( AND( DAY(LastDay__c)>=30, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1), 1, 0)
+ IF( AND( DAY(LastDay__c)>=31, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1), 1, 0)

数式の意味についてはリンク先をご覧いただければと思いますが、上記数式のうち、
DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31)
を見たときにこう思いました。

「この数式、BaseDay__c 次第ではエラーにならない?」

(でも、さすがにブログに書く前に動作確認はしているよなぁ…)と思いつつ、「よく考えたら、AND、ORの条件判定文でエラーが入ったときにどういう処理が行われるか知らないわ」と思ったので、調査することにしました。

AND関数にエラー数式を混ぜる

まず、日付を設定する項目 BaseDay__c と、 DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29)DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30)DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) の数式項目を作成します。 そして、BaseDay__c に様々な日付を設定し、数式項目の結果を確認します。

f:id:mark-hammer:20201113001057p:plain
月末が異なる日付と数式の結果

予想通り、存在しない日付をDATE関数で出力しようとするとエラーになりました。

続いて、ブログを参考に LastDay__c を設定します。
そして、ブログに記載されていた以下数式を少し変更し、月末が異なる日付で出力させてみます。

  • 29日は日曜日?: IF( AND( DAY(LastDay__c)>=29, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1), TRUE, FALSE)
  • 30日は日曜日?: IF( AND( DAY(LastDay__c)>=30, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1), TRUE, FALSE)
  • 31日は日曜日?: IF( AND( DAY(LastDay__c)>=31, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1), TRUE, FALSE)

f:id:mark-hammer:20201113004417p:plain
数式の結果

AND関数の引数にエラーになる数式が入っているはずですが、数式全体としてはエラーになりませんでした。

次に、AND関数の引数の順番を入れ替えます。

  • 29日は日曜日?: IF( AND( WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1, DAY(LastDay__c)>=29), TRUE, FALSE)
  • 30日は日曜日?: IF( AND( WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1, DAY(LastDay__c)>=30), TRUE, FALSE)
  • 31日は日曜日?: IF( AND( WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1, DAY(LastDay__c)>=31), TRUE, FALSE)

論理式であれば X AND YY AND X は同じ結果になるはずですが、どうでしょうか。

f:id:mark-hammer:20201113005238p:plain
数式の結果

今度は存在しない日付の場合はエラーを表示するようになりました。

さらに最初のAND数式を少し変更し、「AND関数の最初の引数は必ずTRUEを返す数式」を設定します。

  • 29日は日曜日?: IF( AND( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1), TRUE, FALSE)
  • 30日は日曜日?: IF( AND( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1), TRUE, FALSE)
  • 31日は日曜日?: IF( AND( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1), TRUE, FALSE)

これは、「LastDay__cの日は28以上である」という、BaseDay__cにどの日付を入れても必ずTRUEになる数式をAND変数の1番目の引数に設定しています。

f:id:mark-hammer:20201113010948p:plain
数式の結果

エラー数式をAND関数の1番目の引数に設定した場合と同じ動作でした。

AND関数の動作推察

このことから、以下の動作になっていると推測できます。

  • AND関数は左の引数からTRUE、FALSEを判定している。
  • 引数の途中でFALSEと判定された場合は、そこで判定を打ち切り、AND関数はFALSEを返す。
    • 最初の日曜日判定で存在しない日付でもエラーにならなかった理由は、 DAY(LastDay__c)>=XX の時点でFALSEと判定されたため、その後のエラー数式が判定されなかったためと推測できます。
  • 引数の途中でエラーと判定された場合は、そこで判定を打ち切り、AND関数はエラーを返す。
  • AND関数の全ての引数がTRUEの場合はTRUEを返す。

OR関数にエラー数式を混ぜる

今度は、OR関数の1番目の引数に必ずTRUEになる数式と必ずFALSEになる数式を設定し、2番目の引数にエラー数式を設定して動作を見てみます。

1番目の引数に必ずTRUEになる数式を設定

  • 29日は日曜日?: IF( OR( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1), TRUE, FALSE)
  • 30日は日曜日?: IF( OR( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1), TRUE, FALSE)
  • 31日は日曜日?: IF( OR( DAY(LastDay__c)>=28, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1), TRUE, FALSE)

動作結果は以下になりました。

f:id:mark-hammer:20201113012128p:plain
数式の結果

OR関数は引数のうち1つでもTRUEがあればTRUEを返すため、期待通りの動作と言えます。

1番目の引数に必ずFALSEになる数式を設定

  • 29日は日曜日?: IF( OR( DAY(LastDay__c)>=32, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 29) ) = 1), TRUE, FALSE)
  • 30日は日曜日?: IF( OR( DAY(LastDay__c)>=32, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 30) ) = 1), TRUE, FALSE)
  • 31日は日曜日?: IF( OR( DAY(LastDay__c)>=32, WEEKDAY( DATE( YEAR( BaseDay__c ), MONTH( BaseDay__c ), 31) ) = 1), TRUE, FALSE)

動作結果は以下になりました。

f:id:mark-hammer:20201113012624p:plain
数式の結果

AND関数にて検証した、「AND数式の最初の引数は必ずTRUEを返す数式」を設定したときと同じ動作でした。

OR関数の動作推察

このことから、以下の動作になっていると推測できます。

  • OR関数は左の引数からTRUE、FALSEを判定している。
  • 引数の途中でTRUEと判定された場合は、そこで判定を打ち切り、OR関数はTRUEを返す。
  • 引数の途中でエラーと判定された場合は、そこで判定を打ち切り、OR関数はエラーを返す。
  • OR関数の全ての引数がFALSEの場合はFALSEを返す。

終わりに

今回の検証にて確認できた、「AND、OR関数にて引数の途中で結果が確定した場合は、最後まで処理を行わずに結果を返す」動作は「短絡評価」といい、Salesforce外のプログラミング言語でも使われています。

ja.wikipedia.org

Salesforce数式を作成するうえではあまり気にしなくてもよい動作かと思いますが*1、「こういう動作なんだ」ということを頭の片隅にでも入れていただければ幸いです。

*1:条件式にエラーになりえる数式を積極的に使う場合は必要ですが…