Adobe Campaignクエリー道場(5)〜CASE式はシティポップに乗せて

『Plastic Love』『都会』『頬に夜の灯』──昭和の「シティポップ」がブームになりましたね。知らないはずなのに知ってるような感じが新鮮でエモい？　それともただひたすら懐かしい？　あなたはどの世代でしょうか。『真夜中のドア』も「ずっと真夜中でいいのに。」もどちらもいける跡部官辺です。
***
世代といえば、刺さるキャンペーンを打つためのオーディエンス属性情報としてマーケティングでは基本中の基本ですね。今回は、Adobe Campaignで以下のような要件を考えてみましょう。

:::note
誕生日が1926年12月26日以降の受信者を「昭和生まれ」「平成生まれ」「令和生まれ」とラベリングしたい。
:::

たとえば1945年8月15日生まれの方は「昭和生まれ」です。2023年1月1日生まれなら「令和生まれ」。──などと生年月日の元号によってラベルを貼るというわけです。

あなたならどう攻めますか。「平成生まれのお客様へ」などとメッセージ文面に差し込むならパーソナライゼーションですね。そもそも誕生日の元号によって配信を出すか出さないか区別するのであれば「分割」アクティビティでしょうか。
それらもいいですが、ここはCampaignクエリー道場。なんとクエリーだけでもラベリングができてしまうのです。さっそくやってみましょう。
***
まずいつものように「クエリ」アクティビティを作成。「受信者」をディメンジョンとし、フィルター条件を定義しましょう:
![2023-11-01_15-15-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/e4371dbd-babe-14a2-b8a4-bb0ce6dd064c.png)
フィルター条件では「誕生日」が1926年12月26日「以降」と指定します。これにより大正以前生まれと無登録とが除外され、昭和初日以降の誕生日が登録された受信者だけが対象となります。「昭和生まれ」「平成生まれ」「令和生まれ」とMECE[^1]に分けられる状態です[^2]:
![2023-11-01_15-19-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/d2475019-d9a9-f6b1-1dee-59c80c8e50e6.png)
「完了」をクリックして画面を戻り、「データを追加...」をクリック:
![2023-11-01_22-10-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/36e5686c-a5f0-0422-0ea8-c40930720cfc.png)
「フィルタリングディメンジョンにリンクされたデータ」を選択して「次へ」:
![2023-11-01_22-04-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/9abaeb35-3bf0-be6e-80d0-2e81c70b70f8.png)
「フィルタリングディメンジョンのデータ」を選択して「次へ」:
![2023-11-01_22-06-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/9ba50500-0b78-238e-484b-07c930a626bc.png)
左ペインからは何も選ばず、「出力列」の「追加」ボタンをクリックします:
![2023-11-01_15-42-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/05870f95-07f7-2c32-0544-e490264b0759.png)
「式」には以下をそのままコピペしてください[^3]。意味はのちほど解説します:
```
Case(When(@birthDate<'1989/01/08', '昭和生まれ'), When(@birthDate<'2019/05/01' and @birthDate>='1989/01/08', '平成生まれ'), Else('令和生まれ'))
```
![2023-11-02_12-03-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/837abefc-496a-6ffc-d29d-09f08f4248a5.png)
「ラベル」と「エイリアス」にはわかりやすい任意の文字列を入力してください。必須ではありません:
![2023-11-01_22-18-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/ee1970d0-99d8-358f-0007-0d50255cdc8d.png)
これも必須ではありませんが見やすさのために、「使用可能フィールド」の「誕生日」をダブルクリックし「出力列」へ追加します:
![2023-11-01_22-23-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/4901474c-4934-6591-3c56-ba6087add11d.png)
「OK」を２回クリックするとワークフローキャンバスに戻ります。実行し、「クエリ」アクティビティからの遷移矢印を右クリックして「ターゲットを表示...」から結果を見てみましょう:
![2023-11-01_16-46-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516149/9ac22019-9e25-066d-d8fb-3da8fc9c357d.png)
誕生日に応じて「昭和生まれ」「平成生まれ」「令和生まれ」とラベルが振られてますね。このフィールドを後続の配信に差し込めば、パーソナライゼーションが省略できます。
***
ここで、さきほどコピペした式の中身を振り返ってみましょう:
```
Case(When(@birthDate<'1989/01/08', '昭和生まれ'), When(@birthDate<'2019/05/01' and @birthDate>='1989/01/08', '平成生まれ'), Else('令和生まれ'))
```
どういう意味でしょうか。「Case()」「When()」「Else()」はそれぞれCampaignの関数です[^4]。これらの関数は単独で使うことはないため、セットで考えてください。
「Case()」は、対象集合の分割をカッコ内に列挙します。その条件を具体的に記述するのが関数「When()」です。
まず「When(＠birthDate<'1989/01/08', '昭和生まれ')」は、「＠birthDate<'1989/01/08'」が真であれば「昭和生まれ」という文字列を返します。誕生日が1989年1月8日より前であるという条件だけ与えれば、受信者のフィルター条件で誕生日が1926年12月26日以降と指定しているので、昭和生まれを必要十分に捕捉可能です。
続いて「When(＠birthDate<'2019/05/01' and ＠birthDate>='1989/01/08', '平成生まれ')」。誕生日が1989年1月8日以降かつ2019年5月1日より前であれば「平成生まれ」という文字列を返します。
そして「Else('令和生まれ')」。上述２条件に当てはまらなければ「令和生まれ」という文字列を返します。ここで効いてくるのが、「MECEに分けられる」という前提。昭和でも平成でもなければ令和、といえるからこそElseをここで使えるのです[^5]。

以上により、コピペした式が誕生日に応じた文字列を返すことがわかりました。
***
この式に対し、バックエンドではこのようなSQLが生成されます:
```
SELECT  DISTINCT  case  when R0.tsBirth < E'1989/01/08' then E'昭和生まれ' when R0.tsBirth < E'2019/05/01' and R0.tsBirth >= E'1989/01/08' then E'平成生まれ' else E'令和生まれ' end, R0.tsBirth, R0.iRecipientId FROM NmsRecipient R0 WHERE (R0.tsBirth >= date '1926-12-26') AND ((R0.iRecipientId > 0 OR R0.iRecipientId < 0))
```
これは、SQLのCASE式といわれるもの。SQLを使いこなすうえでの要諦といっていい大事なテクニックです。
パーソナライゼーションならJavaScriptの「if」を使って条件分岐します。しかしSQLは、JavaScriptのような「手続き型言語」ではありません。そのため本来「if」のような条件分岐を持ちませんでした[^6]。かわりに導入されたのがCASE式。これにより、集合論的なSQLの本質に添いながら、手続き的な条件分岐ができるようになりました。
本稿の要件は単純なようですが、そのクエリーによる実装は、Campaignを背後で支えるSQLのまさに勘所ともいうべきポイント、CASE式を押さえることなのです。

***
いかがでしたか。反射的に「分割」アクティビティやパーソナライゼーションという方もいそうですが、差し込みで文面切り替えのような要件であれば、本稿のように「クエリ」アクティビティでCASE式を使うほうが効率という観点からもおすすめです。
CASE式を使ったクエリーでは、本稿の場合のほかに筆者がちょっと驚いた意外な活用方法もありました。お客様からいただいた実際のケースをもとに、次回ご紹介しますね。お楽しみに。それでは次回もstay with me♪

:::note warn
本稿の内容は筆者のオンプレミス型デモ環境(Adobe Campaign Classic 9359@c636bf3 PostgreSQL 14.9)上で実施した検証に基づきます。別環境における同様の動作を保証するものではありません。またデータは架空のものであり、既存の配信や実在の組織とはいっさい関係がありません。
:::

[^1]: Mutually Exclusive and Collectively Exhaustive。この場合「昭和生まれ」「平成生まれ」「令和生まれ」のいずれかであり、それ以外はないこと。
[^2]: 国籍や誕生地のタイムゾーンは考慮しません。
[^3]: UIからでもできますが、むしろ面倒なので、式の直接入力にしました。
[^4]: https://experienceleague.adobe.com/docs/campaign-classic/using/getting-started/creating-queries/defining-filter-conditions.html?lang=ja#list-of-functions
[^5]: 記事公開日現在。
[^6]: 「ストアドプロシージャ」はSQLではありません。DBMSが個別に実装する機能です。