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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Treasure Data

Treasure Dataは、米国トレジャーデータ社の提供するクラウド型のデータマネジメントサービスです。ビッグデータ処理システムを備え、AWS上にセットアップされているため、データの集収、保管、分析を容易に行うことができます。

Q&A

解決済

1回答

4955閲覧

SQLが作れません...【window関数 COUNT(DISTICT)を代替する方法はないか?】

th1209

総合スコア40

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Treasure Data

Treasure Dataは、米国トレジャーデータ社の提供するクラウド型のデータマネジメントサービスです。ビッグデータ処理システムを備え、AWS上にセットアップされているため、データの集収、保管、分析を容易に行うことができます。

1グッド

0クリップ

投稿2016/07/27 12:59

編集2016/07/28 02:46

いつもお世話になっております。
SQLの作成につまづいており、どなたかご教授いただきたいです。
詳細は以下になります。

<環境>
・クエリ実行環境:TresureData(ビッグデータ集計ツール)
・SQL:presto

<求めたいクエリ>
・ゲームのKPIを求めるクエリです。
・日毎の課金UUの累計を、プラットフォーム毎(iOS,Android)に求めます。
・具体例を示すと、次のような感じです。
date platform uu
2016-01-01 ios 100
2016-01-01 android 70
2016-01-02 ios 120 <- 前日からだんだん累計されていく
2016-01-02 android 130

<困っている点>
・window関数を使って、課金UUの累計を求めようとしています。
ただ、prestoだと、window関数で DISTINCTを使えないようです...。
window関数を代替して、どうにか求める方法はないでしょうか?

<実際のクエリ>

sql

1-- 日別プラットフォーム別に、課金したユーザの一覧を取る 2WITH sub1 AS 3( 4SELECT 5 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') AS date 6 ,{platform} 7 ,user_id 8FROM 9 kpi_table 10WHERE 11 --月初め〜月末まで取る 12 TD_TIME_RANGE( 13 time 14 ,TD_TIME_FORMAT({month_start},'yyyy-MM-dd 00:00:00','JST') 15 ,TD_TIME_FORMAT({month_last},'yyyy-MM-dd 23:59:59','JST') 16 ,'JST' 17 ) 18 --課金したユーザのみ 19 AND (purchase_amount > 0) 20GROUP BY 21 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') 22 ,{platform} 23 ,user_id 24ORDER BY 25 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') ASC 26 ,{platform} ASC 27 ,user_id 28) 29-- 集計 30SELECT 31 date 32 ,{platform} 33 -- Window関数で DISTINCTは未実装のため、ここでエラーになる 34 ,COUNT(DISTINCT user_id) OVER(PARTITION BY {platform} ORDER BY date ASC) AS charging_uu 35FROM 36 sub1 37ORDER BY 38 date 39 ,{platform} 40--...(実際のクエリは、この後も処理が続きます...)

<補足>
・クエリ中の{}で囲っている箇所は、ツールを使って動的に値が入ります。
・代替案として、クエリを日別に生成して(ex 7/1までのSQL、7/2までのSQL、、、)
順にクエリを実行する方法も考えました。
ただ、パフォーマンスに影響する都合上、
クエリの実行は1回に抑えたく、この代替案は取れません。
・クエリはjupyter上から実行しています。
途中まで計算した段階で
pandas-tdライブラリのDataFrameクラスを使い、
jupyter上で集計を行うのもありかと思います。
ただ、jupyterを実行するマシンは、そこまでスペックが高くなく、
jupyter上で集計しようとするとパフォーマンスがでないと思います。
できれば、クエリ上で集計を全て行いたいです。

以上になります。
SQLに詳しい方、ビックデータに詳しい方etc...
ご教授いただけますと幸いですb

20160728追記

  • 一応、window関数とWHERE句を使って書くことはできました(以下になります)。
  • まだ冗長なクエリなので、何かスマートな書き方をご存知な方がいれば、教えていただけますと幸いです...b

sql

1-- 日別プラットフォーム別に、課金したユーザの一覧を取る 2WITH sub1 AS 3( 4SELECT 5 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') AS date 6 ,{platform} 7 ,user_id 8FROM 9 kpi_table 10WHERE 11 --月初め〜月末まで取る 12 TD_TIME_RANGE( 13 time 14 ,TD_TIME_FORMAT({month_start},'yyyy-MM-dd 00:00:00','JST') 15 ,TD_TIME_FORMAT({month_last},'yyyy-MM-dd 23:59:59','JST') 16 ,'JST' 17 ) 18 --課金したユーザのみ 19 AND (purchase_amount > 0) 20GROUP BY 21 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') 22 ,{platform} 23 ,user_id 24ORDER BY 25 TD_TIME_FORMAT(time,'yyyy-MM-dd','JST') ASC 26 ,{platform} ASC 27 ,user_id 28) 29-- ユーザ毎のログイン日を集計 30, sub2 AS 31( 32SELECT 33 date 34 ,{platform} 35 ,user_id 36 ,COUNT(user_id) OVER (PARTITION BY {platform}, user_id ORDER BY date) AS login_count 37FROM 38 sub1 39ORDER BY 40 date ASC 41 ,{platform} ASC 42 ,user_id 43) 44-- 全ユーザのログイン日を集計 45, sub3 AS 46( 47SELECT 48 date 49 ,{platform} 50 ,COUNT(user_id) OVER (PARTITION BY platform ORDER BY date) user_num 51FROM 52 sub2 53--最初にログインした日以外のデータは排除 54WHERE 55 login_count = 1 56ORDER BY 57 date ASC 58 ,{platform} ASC 59) 60-- データを日別 * プラットフォーム別に絞る 61SELECT 62 date 63 ,{platform} 64 MAX(user_num) AS user_num 65FROM 66 sub3 67GROUP BY 68 date 69 ,{platform} 70ORDER BY 71 date ASC 72 ,{platform} ASC
9nom👍を押しています

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

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

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

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

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

Panzer_vor

2016/07/27 13:26

こんばんは。 prestoノータッチなんですが一点気になったので質問をば。 WITH句内のクエリでuser_idがGROUP BY対象となってないのに、 SELECT句で選択されています。 これはクエリがエラーとならないとしても、 取得するuser_idが不定となり意図したものと異なる値が取得されていたりなどしませんでしょうか?
th1209

2016/07/28 02:33

KotoriMaturiさん ご指摘ありがとうございます。 おっしゃるとおりで、WITH句内のGROUP BY句にはuser_idが入りますね...。 (転記する際に間違えていたみたいです。修正しておきますね!)
guest

回答1

0

ベストアンサー

以下のようにCOUNT文の中のDISTINCTを除いてはダメですか?

sql

1COUNT(user_id) OVER(PARTITION BY {platform} ORDER BY date ASC) AS charging_uu

sub1のWITH句の中で、GROUP BY 句にuser_idを指定しているので、user_idは重複していないように思います。
なので、DISTINCTを取り払っても良いのでは?と思いました。

投稿2016/08/13 07:22

yuji38kwmt

総合スコア437

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

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

th1209

2016/08/28 09:06

yuji38kwmtさん ご回答ありがとうございます! (ご回答に気づくのが遅れてしまい、申し訳ありません...。) おっしゃる通り、先行するWITH句で、user_id毎にGROUP BYをかけているため、 そもそもDISCINCT要りませんよね(笑) 先ほど試しに実行してみたのですが、これで問題なく動作しました! おかげで、この箇所のクエリ、すっきりしたものに直せそうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問