質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Amazon Redshift

Amazon Redshiftは、Amazon社が提供する 高速かつ完全マネージド型でペタバイト規模の クラウドデータウェアハウスサービスです。

Q&A

解決済

1回答

1697閲覧

新規、復帰ユーザー抽出

sato_day

総合スコア20

Amazon Redshift

Amazon Redshiftは、Amazon社が提供する 高速かつ完全マネージド型でペタバイト規模の クラウドデータウェアハウスサービスです。

0グッド

0クリップ

投稿2017/11/07 05:26

編集2017/11/07 05:27

またも質問させていただきます!

以下のようなテーブルがあり、以下3条件で抽出したいのですがうまくいきません。

①2017/5/1以降に購入したユーザー数
②2017/5/1以降初めて購入ユーザー数
③2017/5/1以降に、1年&6ヶ月以上購入がなかった復帰ユーザー数

■テーブル名:purchase

date uid
2017/4/30 1111
2017/5/1 1111
2017/5/2 1111
2016/4/1 2222
2017/5/1 2222
2016/11/1 3333
2017/5/1 3333
2017/5/1 4444
2017/5/1 5555
2017/5/2 5555
2017/5/3 5555

①と②は以下で出るかと思ったのですが、ttlとfstの値が同じになってしまいます、、

SQL

1select 2 count(distinct case when date >= '2017-05-01' then uid else null end) as ttl 3 ,count(distinct case when first_order >= '2017-05-01' then uid else null end) as fst 4 ,count(distinct case when first_order < '2017-05-01' then uid else null end) as rep 5FROM( 6select 7 uid 8   ,date 9 ,MIN(date) as first_order 10 from purchase 11 GROUP BY 1,2 12) z 13

また、③は以下にすると5/1以降に初めて購入したユーザーが含まれてしまうので
うまくいきません。。

SQL

1select 2 count(distinct case when last_odr - first_odr > 365 then a.uid else null end) as r_y 3 ,count(distinct case when last_odr - first_odr > 180 and last_odr - first_odr <= 365 then a.uid else null end) as r_m 4FROM( 5select 6 uid 7 ,MIN(date) as last_odr 8 from purchase 9 where date >= '2017-05-01' 10 GROUP BY 1 11) as a 12left join(select 13 uid 14 ,MIN(date) as first_odr 15 from purchase 16 where date < '2017-05-01' 17 GROUP BY 1 ) as b on a.uid = b.uid

恐れいりますが、ご教示

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaya_ohashi

2017/11/07 05:55

③2017/5/1以降に、1年&6ヶ月以上購入がなかった復帰ユーザー数の定義がいまいちわかりません。1年6ヶ月という期間はどこを起点にどこまでですか?2017年5月1日より前の最後の買い物から、5月1日以降最初の買い物の期間という認識で合っていますか?
sato_day

2017/11/07 06:07

大変ん失礼しました、、、2017/5/1以降に注文があったユーザーの中で1年たっての復帰した人と、6ヶ月たっての復帰をそれぞれ出したく、
masaya_ohashi

2017/11/07 06:08

つまり、5月1日以降の最初の買い物から遡って、前回の買い物から1年以上の人、6ヶ月以上の人の数、ということですね?これは6ヶ月以上には1年以上の人が含まれますか?
masaya_ohashi

2017/11/07 06:08

あ、よく見たら下のSQLでは含めないようにしていますね
masaya_ohashi

2017/11/07 06:09

これはワンクエリでttlとfstとrepが取れないとだめな要件ですか?
sato_day

2017/11/07 06:14 編集

■1年復帰 ・・・ 2017/5/1以降に購入した人のうち、1年以上買い物履歴がなかった方 ■6ヶ月復帰・・・ 2017/5/1以降に購入した人のうち、6ヶ月以上買い物履歴がなかった方 という意味でした。。失礼しました。
sato_day

2017/11/07 06:15

いえ、ぜんぜんワンクエリではなくても大丈夫です、数字さえ出れば!
masaya_ohashi

2017/11/07 06:21

確認ですが、1年は365日、6ヶ月は180日の固定値でよいのでしょうか?例えばうるう年や大の月は計算に入れないでよいのでしょうか?
sato_day

2017/11/07 06:34

あ、そこはもうだいたいでいいので1年365日、6ヶ月は180日固定で大丈夫です!
guest

回答1

0

ベストアンサー

まず集計に必要なデータが何なのかを考えましょう。
①の条件を検索するには「全てのユーザの、全ての購入についての日付」が必要です。
②の条件を検索するには「全てのユーザの、2017−05-01以降の最初の購入日付」が必要です。
③の条件で検索するには「全てのユーザの、2017-05-01より前の最後の購入、2017-05-01以降の最初の購入の空白期間の日数」が必要です。

それらを得られるクエリがまずこちらになります。
※SQLの予約語は全て大文字にして見分けやすくしています。

SQL

1SELECT 2 purchase.uid 3 ,date 4 ,first_order 5 ,DATEDIFF(first_order_after_may_first, last_order_before_may_first) AS blank_days 6FROM purchase 7 # 全期間を通して最初の購入をfirst_orderとする 8 LEFT JOIN ( 9 SELECT 10 uid 11 ,MIN(date) AS first_order 12 FROM purchase 13 GROUP BY uid 14 ) AS first_orders ON purchase.uid = first_orders.uid 15 # 2017-05-01以降の最初の購入をfirst_order_after_may_firstとする 16 LEFT JOIN ( 17 SELECT 18 uid 19 ,MIN(date) AS first_order_after_may_first 20 FROM purchase 21 WHERE date >= '2017-05-01' 22 GROUP BY uid 23 ) AS first_order_after_may_firsts ON purchase.uid = first_order_after_may_firsts.uid 24 # 2017-05-01より前の最後の購入をlast_order_before_may_firstとする 25 LEFT JOIN ( 26 SELECT 27 uid 28 ,MAX(date) AS last_order_before_may_first 29 FROM purchase 30 WHERE date < '2017-05-01' 31 GROUP BY uid 32 ) AS last_order_before_may_firsts ON purchase.uid = last_order_before_may_firsts.uid;

そして、こちらのテーブルを元に、①②③(③は半年、1年それぞれ)を得たものがこちらになります。

SQL

1 2SELECT 3 COUNT(DISTINCT CASE WHEN date >= '2017-05-01' THEN uid ELSE NULL END) as ttl 4 ,COUNT(DISTINCT CASE WHEN first_order >= '2017-05-01' THEN uid ELSE NULL END) as fst 5 ,COUNT(DISTINCT CASE WHEN blank_days > 180 AND blank_days < 365 THEN uid ELSE NULL END) AS rep180 6 ,COUNT(DISTINCT CASE WHEN blank_days >= 365 THEN uid ELSE NULL END) AS rep365 7FROM ( 8 SELECT 9 purchase.uid 10 ,date 11 ,first_order 12 ,DATEDIFF(first_order_after_may_first, last_order_before_may_first) AS blank_days 13 FROM purchase 14 # 全期間を通して最初の購入をfirst_orderとする 15 LEFT JOIN ( 16 SELECT 17 uid 18 ,MIN(date) AS first_order 19 FROM purchase 20 GROUP BY uid 21 ) AS first_orders ON purchase.uid = first_orders.uid 22 # 2017-05-01以降の最初の購入をfirst_order_after_may_firstとする 23 LEFT JOIN ( 24 SELECT 25 uid 26 ,MIN(date) AS first_order_after_may_first 27 FROM purchase 28 WHERE date >= '2017-05-01' 29 GROUP BY uid 30 ) AS first_order_after_may_firsts ON purchase.uid = first_order_after_may_firsts.uid 31 # 2017-05-01より前の最後の購入をlast_order_before_may_firstとする 32 LEFT JOIN ( 33 SELECT 34 uid 35 ,MAX(date) AS last_order_before_may_first 36 FROM purchase 37 WHERE date < '2017-05-01' 38 GROUP BY uid 39 ) AS last_order_before_may_firsts ON purchase.uid = last_order_before_may_firsts.uid 40 ) AS purchase;

投稿2017/11/07 06:37

masaya_ohashi

総合スコア9206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sato_day

2017/11/08 08:16 編集

すっごく理解しました!以下エラーとなったのですが、以下にしたら出ました!!DATEDIFF(day,first_order_after_may_first, last_order_before_may_first) AS blank_days
sato_day

2017/11/08 08:17

ただ、以下の数字が同じで抽出されてしまったのでこちらはもう少し考えたいとおもいます!COUNT(DISTINCT CASE WHEN date >= '2017-05-01' THEN uid ELSE NULL END) as ttl ,COUNT(DISTINCT CASE WHEN first_order >= '2017-05-01' THEN uid ELSE NULL END) as fst
masaya_ohashi

2017/11/08 08:28

それはですね、そちらの書かれたSQLだとuidとdateでグルーピングしたものの中からMINで最小の日付を探しているので、意図した動作になっていないからです。試しにサブクエリの部分だけ抜き出して実行してみてください。first_orderがおかしなことになるはずです。 select uid    ,date ,MIN(date) as first_order from purchase GROUP BY 1,2 ;
masaya_ohashi

2017/11/08 08:30

first_orderはユーザでのグルーピング内でMINを求めなければならないのに、ユーザと日付2つのカラムでグルーピングしたものからMINを求めているのでdateとfirst_orderが必ずイコールになります。なので、以下のクエリはまったく同じ結果になるのです。 COUNT(DISTINCT CASE WHEN date >= '2017-05-01' THEN uid ELSE NULL END) as ttl ,COUNT(DISTINCT CASE WHEN first_order >= '2017-05-01' THEN uid ELSE NULL END) as fst
sato_day

2017/11/08 08:52

あーーーーーーーーーーーーーーーーーなるほどなるほどそうですよね、、失礼しました。一番出したかったのは③で、それがばっちりでたのでとっても助かりました、勉強になりました!頭が固いのか、いろいろ考えが及ばないのですが精進いたします!!
masaya_ohashi

2017/11/08 09:02

まあこういう発想は経験の数がものをいうので、いろいろなことにぶつかっていってください。そのうち「あ、ここ進研ゼミでやったとこだ!」のような感覚で問題が解けるようになります。
sato_day

2017/11/08 09:51

進研ゼミwwww まず思ったことを形にする想像力が足りない気がするので、映画とかみてイマジネーション力を身につけたいと思います、、(違
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問