困っていること:
AWS Athena SQL(presto)またはPostgreSQL v13 で下記のような集計をしたいと考えています。
カード会員情報テーブルから、各カード番号の最新カード番号を求めて、
最新カード番号で売上を集計したいのですが、当方のSQLの知見では、どのように求めてよいのかわからず、
方法についてご教授いただけましたら幸いです。
前提条件:
・下記の2つのテーブルがあります。
A:ポイントカード会員の会員番号を格納した会員情報テーブル
B:会員の売上明細テーブル
・Aの会員番号テーブルはカードの紛失や再発行などで、会員のカード番号が切り替わることがあります。
その場合、新規にカード番号が追加され、切替前カード番号欄に、以前のカード番号が入力されます。
下記表の例では切替前後のカード番号に法則性があるようにも見えますが、実際には
切替前後のカード番号に規則性(先頭○桁目が同じだったり、前の番号の方が若いなど)はありません。
切り替わった後の旧カード番号のis_experedには、フラグ1が入ります。有効の場合はnullです。
切替え可能回数に制限はありません。
・売上明細テーブル上のカード番号は、販売時点のカード番号のままです。
<テーブルのイメージ>
A:カード会員情報:CardMembers
求めたい集計結果
単純にカード番号ごとに集計しただけだと、本来切替前後で同じ会員であるにも関わらず、カード番号がわかれているため、
別の会員番号ごとに集計されています。
これらをまとめて一つの会員番号(最新会員番号)ごとに集計したいと考えています。
※最終的に求めたい結果は下記③ですが、そのためには下記、①→②→③の順番で処理していく必要があると考えています。
①カード会員情報テーブルの各カード番号に最新のカード番号を付与(切替前カード番号からたどって最新カード番号を更新)
② Bの売上明細に、上記①をleft join しての最新カード番号 を各明細に付与
③上記テーブル②でセットした最新カード番号をもとにGROUP BYして最新カード番号ごとに売上を集計する
検討したこと
上記①を以下に求めるかがポイントだとわわかるのですが、その方法がわかりません。
1世代、2世代、3世代などカード切替の世代が限定されている場合は自己結合で出来るかと思うのですが、
今回のように、会員によっては、世代がバラバラの場合、再帰的に世代をさかのぼる必要があると思われました。
私の思いつく範囲、調べた範囲で試してみたこととしては、下記のようなSQLになります。
下記の方法だと4世代前のカード番号までは遡って、集計出来るかと思いますが、
5世代、6世代とさかのぼるには、さらにLEFT JOINを繰り返す必要があり
冗長なSQLとなってしまいます。
再帰的にCardMembersを参照するなどしてもっとシンプルなSQLにできないものかと考えています。
よりよいやりかたがございましたら、ご教授いただけましたら幸いです。
<サンプルSchema>
sql
1--サンプルSchema PostgreSQL v13 で試しています 2 3CREATE TABLE CardMembers ( 4 card_no INTEGER NOT NULL PRIMARY KEY, 5 prev_card_no INTEGER, 6 is_expired INTEGER); 7 8INSERT INTO CardMembers VALUES (10005,10004,NULL); 9INSERT INTO CardMembers VALUES (10004,10003,1); 10INSERT INTO CardMembers VALUES (10003,10002,1); 11INSERT INTO CardMembers VALUES (10002,10001,1); 12INSERT INTO CardMembers VALUES (10001,NULL,1); 13INSERT INTO CardMembers VALUES (20002,20001,NULL); 14INSERT INTO CardMembers VALUES (20001,NULL,1); 15 16 17CREATE TABLE Sales(card_no INTEGER NOT NULL, 18sales_amount INTEGER NOT NULL, 19sales_date VARCHAR NOT NULL, 20 PRIMARY KEY (card_no,sales_amount,sales_date)); 21 22INSERT INTO Sales VALUES (10005,300,'20220103'); 23INSERT INTO Sales VALUES (10004,500,'20220102'); 24INSERT INTO Sales VALUES (10003,200,'20220101'); 25INSERT INTO Sales VALUES (10002,100,'20211231'); 26INSERT INTO Sales VALUES (10001,1000,'20221230'); 27 28INSERT INTO Sales VALUES (20002,300,'20211229'); 29INSERT INTO Sales VALUES (20001,400,'20211228');
<試してみたSELECT文>
4世代前のカード番号まで遡って集計可能
sql
1 2SELECT COALESCE(C4.card_no, C3.card_no, C2.card_no, C1.card_no, Sales.card_no) card_no 3, SUM(Sales.sales_amount) sales_amount 4FROM Sales 5LEFT JOIN CardMembers AS C1 ON Sales.card_no = C1.prev_card_no 6LEFT JOIN CardMembers AS C2 ON C1.card_no = C2.prev_card_no 7LEFT JOIN CardMembers AS C3 ON C2.card_no = C3.prev_card_no 8LEFT JOIN CardMembers AS C4 ON C3.card_no = C4.prev_card_no 9GROUP BY COALESCE( C4.card_no, C3.card_no, C2.card_no, C1.card_no, Sales.card_no) 10 11
回答1件
あなたの回答
tips
プレビュー