2

いくつかありますが。質問来る閉じる。私が望むものに(そして私がこのスタックオーバーフローを書いているときに、さらにいくつかを示唆しましたが、どれも私の問題を完全に捉えていません)、SQLの茂みから抜け出す方法を見つけることができないようです。

ユーザー、週、クラスの3つのフィールドを持つ単一のテーブル(user_classification_fctと呼びます)があります(たとえば、第1週のユーザー#1には「通常のユーザー」のクラスがあり、第1週のユーザー#2には'Infrequent User'のクラス)。(余談です、クラスをINTとして実装しましたが、SQLを整理する際に、VARCHARの形式で読みやすいものを使用したいと考えていました。)

私がやりたいのは、ユーザーの行動が次のように全体としてどのように変化しているかの要約レポートを作成することです

  1. 第1週と第2週の両方で通常のユーザーであった50人のユーザーがいました...
  2. 第1週には通常のユーザーでしたが、第2週にはまれなユーザーに落ちたユーザーが10人いました。
  3. 第1週の頻度が低いものから第2週の通常のユーザーに変わったユーザーは5人でした
  4. ... 等々 ...

これを少し注意が必要なのは、ユーザー#5000が第2週にサービスの使用を開始しただけで、第1週のテーブルにレコードがない可能性があることです。その場合、第1週と2週目の「通常のユーザー」(または適切なもの)。テーブルのサイズは厳密には関係ありませんが、5週間分のデータでは、4,200万行を見ているので、4を挿入したくありません。 5週目かそこらでサービスの使用を開始した人のための「非ユーザー」の偽の行。

私には、これは明らかにMySQLでLEFTまたはRIGHT JOINを使用する場合のように見えます。これは、「欠落している」レコードでNULLが発生するためです。

LEFT JOINでWHERE条件とAND条件の両方を使用しようとしましたが、「正しい」答えが得られません(つまり、WHERE条件の末尾の場合、NULL値がまったく得られないか、カウントが多すぎます。以下で使用されるAND制約の場合、個別のユーザーの数(約1,000万)。これを機能させるための最後の試みは次のとおりです。

SELECT
    ucf1.class_nm AS 'Class in 2012/15',
    ucf2.class_nm AS 'Class in 2012/16',
    ucf3.class_nm AS 'Class in 2012/17',
    ucf4.class_nm AS 'Class in 2012/18',
    ucf5.class_nm AS 'Class in 2012/19',
    count(*) AS 'Count'
FROM
    user_classification_fct ucf5
LEFT JOIN user_classification_fct ucf4 
    ON ucf5.user_id=ucf4.user_id 
        AND ucf5.week_key=201219 AND ucf4.week_key=201218
LEFT JOIN user_classification_fct ucf3 
    ON ucf4.user_id=ucf3.user_id 
       AND ucf4.week_key=201218 AND ucf3.week_key=201217
LEFT JOIN user_classification_fct ucf2 
    ON ucf3.user_id=ucf2.user_id 
       AND ucf3.week_key=201217 AND ucf2.week_key=201216
LEFT JOIN user_classification_fct ucf1 
    ON ucf2.user_id=ucf1.user_id 
       AND ucf2.week_key=201216 AND ucf1.week_key=201215
GROUP BY 1,2,3,4,5;

stackoverflow.comで他のさまざまな質問を見ると、一度に1つずつクエリを実行し、結果セットをUNIONするか、括弧を使用して相互にチェーンする必要があるかもしれませんが、アプローチは(まだ)私が精通しているものではなく、有用なものを返すために1つのLEFT JOIN(つまり、5週目から1週目まで)を取得することさえできません。

データベース製品の切り替えはオプションではないため、ヒントは大いにありがたいです。MySQLで機能する提案をいただければ幸いです。

4

1 に答える 1

1

によるグループ化でこれを行うことができます。まず、5週間のすべての可能な組み合わせを次のように要約します。

select c_201215, c_201216, c_201217, c_201218, c_201219,
       count(*) as cnt
from (select user_id,
             max(case when week_key=201215 then class_nm end) as c_201215,
             max(case when week_key=201216 then class_nm end) as c_201216,
             max(case when week_key=201217 then class_nm end) as c_201217,
             max(case when week_key=201218 then class_nm end) as c_201218,
             max(case when week_key=201219 then class_nm end) as c_201219
      from user_classification_fct  ucf
      group by user_id
     ) t
group by c_201215, c_201216, c_201217, c_201218, c_201219

これで問題が解決する場合があります。5つのクラス(NULLを含む)がある場合、これは最大5^5または3,125行を返します。

これはExcelに適合するので、そこで最終処理を行うことができます。または、データベースを引き続き使用することもできます。

週のペアを抽出したい場合は、上記を一時的なテーブルに入れて「t」と言うことをお勧めします。そして、ユニオンで一連の抽出を実行します。

select *
from ((select '201215' as weekstart, c_201215, c_201216, sum(cnt) as cnt
       from t
       group by c_201215, c_201216
      ) union all
      (select '201216', c_201216, c_201217, sum(cnt) as cnt
       from t
       group by c_201216, c_201217

      ) union all
      (select '201217', c_201217, c_201218, sum(cnt) as cnt
       from t
       group by c_201217, c_201218

      ) union all
      (select '201218', c_201218, c_201219, sum(cnt) as cnt
       from t
       group by c_201218, c_201219
      )
     ) tg
order by 1, cnt desc

このような大きなテーブルでcommon-subqueryの最適化についてメッセージを送りたくないので、サブクエリに入れることをお勧めします。最初に要約し、次にデータをまとめることで、最終的な答えが得られます。

于 2012-08-15T13:14:40.103 に答える