###会員ステータス管理のテーブルからそのステータスであった期間を集計したい
会員ID,入退会区分,入退会日,コース というカラムで構成されたテーブルがあります。
入退会日はvarcharでyyyymmddの形で値が入っています。
会員ID | 入退会区分 | 入退会日 | コース |
---|---|---|---|
0001 | 1 | 20180101 | おためしコース |
0001 | 9 | 20180110 | |
0001 | 2 | 20180115 | 本格コース |
0001 | 9 | 20180120 | |
0002 | 1 | 20180101 | おためしコース |
0002 | 9 | 20180110 | |
0002 | 2 | 20180115 | 本格コース |
0002 | 9 | 20180120 |
入退会区分のフラグは以下のとおりです。
- 0:コース変更
- 1:入会
- 2:再入会
- 3:継続
- 8:退会取消
- 9:退会
入会はどのユーザーでも1回しか存在しません。
その後退会して再入会したときには同じ会員IDで再入会できます。
1は最初の入会で一つだけ、
2再入会と9退会は複数回あれば対になります。
ただ、今回は再入会している人は人数が少ないため無視してもよいとしています。
yyyy年に入会した人が
- 今も継続している
- yyyy+1年で退会している人数
- yyyy+2年で退会している人数
- yyyy+3年で退会している人数
を出したいです。
アウトプットのイメージとしては縦軸に入会年、
横軸に退会年と会員IDで紐付いた別テーブルで持っている会員ランク(A~C)も絡めて出力したいです。
2018A | 2018B | 2018C | 2019A | 2019B | 2019C | 2020A | 2020B | 2020C | |
---|---|---|---|---|---|---|---|---|---|
2018 | 10 | 5 | 3 | 10 | 5 | 3 | 10 | 5 | 3 |
2019 | - | - | - | 8 | 5 | 8 | 5 | 8 | 5 |
2020 | - | - | - | - | - | - | 3 | 8 | 5 |
退会日-入会日が同じ年か1年後か2年後か…
入会日しか存在しないかを分けて出力する方法を模索したのですが
うまく出せる方法が導き出せませんでした。
ご教示いただけないでしょうか。
環境
macローカル PostgreSQL 13.4(pgadmin4)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/21 16:35
回答1件
0
ベストアンサー
同一の会員IDにおいても
入会と退会がセットになった時点でカウントアップするものとします。
SQL
1CREATE TABLE 会員マスタ 2( 3 会員ID varchar(10) 4 , 会員ランク varchar(5) 5); 6 7CREATE TABLE ステータス管理 8( 9 会員ID varchar(10) 10 , 入退会区分 varchar(3) 11 , 入退会日 char(8) 12); 13 14INSERT INTO 会員マスタ 15 ( 会員ID, 会員ランク ) 16VALUES 17 ( '0001', 'A' ) 18 , ( '0002', 'B' ) 19 , ( '0003', 'C' ) 20 , ( '0004', 'A' ) 21 , ( '0005', 'B' ) 22 , ( '0006', 'C' ) 23 , ( '0007', 'A' ) 24 , ( '0008', 'B' ) 25; 26 27INSERT INTO ステータス管理 28 ( 会員ID, 入退会区分, 入退会日 ) 29VALUES 30 ( '0001', '1', '20180101' ) 31 , ( '0001', '9', '20180110' ) 32 , ( '0001', '2', '20180115' ) 33 , ( '0001', '9', '20180120' ) 34 , ( '0002', '1', '20190101' ) 35 , ( '0002', '9', '20190110' ) 36 , ( '0002', '2', '20190115' ) 37 , ( '0002', '9', '20200120' ) 38 , ( '0003', '1', '20180115' ) 39 , ( '0003', '9', '20201231' ) 40 , ( '0004', '1', '20180101' ) 41 , ( '0004', '9', '20210331' ) 42 , ( '0005', '1', '20180120' ) 43 , ( '0006', '1', '20190331' ) 44 , ( '0007', '1', '20200115' ) 45 , ( '0007', '9', '20200115' ) 46 , ( '0007', '2', '20200115' ) 47 , ( '0008', '1', '20201201' ) 48;
SQL
1WITH step1 ( 会員ID, 区分, 入退会日, 枝番 ) AS 2( 3 SELECT 会員ID 4 , ( 入退会区分::int + 3 ) / 2 - 1 5 , 入退会日::date 6 , sum( case when 入退会区分 in ( '1', '2' ) then 1 else 0 end ) 7 over( partition by 会員ID 8 order by 入退会日, ( 入退会区分::int + 1 ) % 2, 入退会区分::int 9 ) 10 FROM ステータス管理 11 WHERE 入退会区分 IN ( '1', '2', '9' ) 12 /* 集計対象を2018年以降に入会した会員に限定しています。 13 不要なら以下の条件は削除して下さい */ 14 AND 入退会日::date >= date_trunc( 'year', now() - interval '3 year' ) 15), 16 step2 ( 会員ID, 会員ランク, 枝番, 入会年, 在籍年数 ) AS 17( 18 SELECT x.会員ID 19 , x.会員ランク 20 , y.枝番 21 , date_part( 'year', max( y.入退会日 ) filter( where 区分 = 1 ) ) 22 , extract( year from 23 age( max( y.入退会日 ) filter( where 区分 > 1 ) -- 退会 24 , max( y.入退会日 ) filter( where 区分 = 1 ) -- 入会 25 ) 26 ) 27 FROM 会員マスタ x 28 JOIN step1 y 29 USING ( 会員ID ) 30 GROUP BY x.会員ID 31 , x.会員ランク 32 , y.枝番 33) 34 35SELECT 入会年 36 , sum(1) filter( where 在籍年数 is null ) 継続 37 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'A' ) A_2018 38 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'B' ) B_2018 39 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'C' ) C_2018 40 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'A' ) A_2019 41 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'B' ) B_2019 42 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'C' ) C_2019 43 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'A' ) A_2020 44 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'B' ) B_2020 45 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'C' ) C_2020 46 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'A' ) A_2021 47 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'B' ) B_2021 48 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'C' ) C_2021 49 FROM step2 50WHERE 入会年 Is Not Null 51GROUP BY 入会年 52ORDER BY 入会年 53;
result
1 2入会年 継続 A_2018 B_2019 A_2020 B_2020 C_2020 A_2021 3-------------------------------------------------------------- 4 2018 1 2 1 1 5-------------------------------------------------------------- 6 2019 1 1 1 7-------------------------------------------------------------- 8 2020 2 1 9--------------------------------------------------------------
追記:
コメント欄で返信したインラインビューを用いた一筆書きのSQLです
SQL
1SELECT 入会年 2 , sum(1) filter( where 在籍年数 is null ) 継続 3 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'A' ) A_2018 4 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'B' ) B_2018 5 , sum(1) filter( where 入会年 + 在籍年数 = 2018 and 会員ランク = 'C' ) C_2018 6 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'A' ) A_2019 7 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'B' ) B_2019 8 , sum(1) filter( where 入会年 + 在籍年数 = 2019 and 会員ランク = 'C' ) C_2019 9 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'A' ) A_2020 10 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'B' ) B_2020 11 , sum(1) filter( where 入会年 + 在籍年数 = 2020 and 会員ランク = 'C' ) C_2020 12 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'A' ) A_2021 13 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'B' ) B_2021 14 , sum(1) filter( where 入会年 + 在籍年数 = 2021 and 会員ランク = 'C' ) C_2021 15FROM 16( 17 SELECT x.会員ID 18 , x.会員ランク 19 , y.入退会区分 20 , date_part( 'year', y.入退会日::date ) 入会年 21 , extract( year from 22 age( lead( y.入退会日, 1 ) 23 over( partition by y.会員ID 24 order by y.入退会日 25 , ( y.入退会区分::int + 1 ) % 2 26 , y.入退会区分::int 27 )::date 28 , y.入退会日::date 29 ) 30 ) 在籍年数 31 FROM 会員マスタ x 32 JOIN ステータス管理 y 33 USING ( 会員ID ) 34 WHERE y.入退会区分 IN ( '1', '2', '9' ) 35 AND y.入退会日::date >= date_trunc( 'year', now() - interval '3 year' ) 36) q 37WHERE 入退会区分 IN ( '1', '2' ) 38GROUP BY 入会年 39ORDER BY 入会年 40;
2021/10/31 コメント欄にいただいたご要望を追記:
「ステータス管理」で完結する形で、入会年と退会年のクロス集計をしたい
SQL
1SELECT 入会年 2 , sum(1) filter( where 在籍年数 is null ) 継続 3 , sum(1) filter( where 入会年 + 在籍年数 = 2018 ) _2018 4 , sum(1) filter( where 入会年 + 在籍年数 = 2019 ) _2019 5 , sum(1) filter( where 入会年 + 在籍年数 = 2020 ) _2020 6 , sum(1) filter( where 入会年 + 在籍年数 = 2021 ) _2021 7FROM 8( 9 SELECT 会員ID 10 , 入退会区分 11 , date_part( 'year', 入退会日::date ) 入会年 12 , extract( year from 13 age( lead( 入退会日, 1 ) 14 over( partition by 会員ID 15 order by 入退会日 16 , ( 入退会区分::int + 1 ) % 2 17 , 入退会区分::int 18 )::date 19 , 入退会日::date 20 ) 21 ) 在籍年数 22 FROM ステータス管理 23 WHERE 入退会区分 IN ( '1', '2', '9' ) 24 AND 入退会日::date >= date_trunc( 'year', now() - interval '3 year' ) 25) q 26WHERE 入退会区分 IN ( '1', '2' ) 27GROUP BY 入会年 28ORDER BY 入会年 29;
投稿2021/10/21 14:11
編集2021/10/31 08:52総合スコア335
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/21 16:45
2021/10/21 21:08
2021/10/22 16:05
2021/10/23 13:04 編集
2021/10/31 08:20
2021/10/31 08:53
2021/10/31 17:33
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。