1

皆さん、こんばんは。

私は一日中これと格闘してきました。

顧客テーブルで、顧客がサブスクライバーになった回数を表示する列を更新しようとしています。このテーブルは、顧客ごとに個別の行を持つビッグ データ ダンプから作成され、毎月、顧客はサブスクライバーでした (毎月の反復番号が割り当てられます)。名前はユニークです。これは次のように表示され、(たとえば) Jane Doe が期間 1000 では購読者であったが、期間 1002 では購読者でなかったことを示しています。

Row_ID Customer_Name  Date_Code 
1      Jane Doe       1000      
2      Jane Doe       1001      
3      Jane Doe       1004      
4      Jane Doe       1005      
5      Ted Jones      1000      
6      Ted Jones      1001      
7      Ted Jones      1002      
etc...

この場合、Jane Doe は 1000 ~ 1001 のサブスクライバーでしたが、サブスクリプションを終了し、1004 ~ 1005 から戻ってきました。すべての日付ロジック (開始日、終了日、日付コードなど) を含むマスター テーブルがあります。おおよそ次のようになります。

Start_Date   End_Date    Date_Code
1990-01-01   1990-03-31  1000
1990-04-01   1990-06-30  1001
1990-07-01   1990-09-30  1002
1990-10-01   1990-12-31  1003
etc...

出力を次のようにする方法を見つけようとしています。

Customer_Name  Subscription_Count
Jane Doe       2
Ted Jones      1

誰かが前にこのようなことに遭遇したことがありますか? 数値が連続している (または連続していない) こと、およびサンプル全体を表している (またはしていない) ことは (人間として) 明らかですが、MYSQL にそれを理解させる方法がわかりません。アイデアをいただければ幸いです。

*編集 - Join と Where Not Exists の両方の選択肢を試しましたが、どちらも 10 分後にタイムアウトしました。メインテーブルのサイズ(〜100,000行)が原因だと思います。何か提案はありますか?コメントありがとうございます。

**編集 #2 - インデックスを追加してテーブルを少し調整した後、両方のソリューションがうまく機能します。これを理解する上でのサポートにもう一度感謝します。

4

2 に答える 2

1

クエリは次のようになります。

SELECT customer_name, count(*) AS subscriptions
FROM   tbl AS t
WHERE NOT EXISTS (
    SELECT *
    FROM tbl AS t1
    WHERE t1.customer_name = t.customer_name
    AND t1.date_code = t.date_code + 1
    )
GROUP BY customer_name;

ここでの秘訣は、顧客の一連のdate_codeごとに1つを除くすべての行を除外してからカウントすることです。つまり、ブロックごとの最後の行にのみ後継(date_code + 1)がありません。

連続するdate_codeが1つのサブスクリプションを形成すると想定しています(質問に対する私の最初のコメントによる)。したがって、およびに関する追加情報Start_DateEnd_Date必要ありません。


パフォーマンス

LEFT JOIN / IS NULL実際には、MySQLよりも少し高速である必要がありNOT EXISTSます(@nnicholsが提供されているため)。
パフォーマンスにとってはるかに重要なのはインデックスです。customer_nameこれを高速にするには、にインデックスが必要ですdate_code。このような:

CREATE INDEX tbl_customer_name ON tbl(customer_name);
CREATE INDEX tbl_date_code ON tbl(date_code);
于 2012-03-11T02:34:32.893 に答える
1

これがまだ当てはまると100%確信することはできませんが、LEFT JOIN / IS NULLは一般的にMySQLのNOT EXISTSよりも高速です-

SELECT t1.customer_name, COUNT(*) AS subscriptions
FROM   tbl t1
LEFT JOIN tbl t2
    ON t1.customer_name = t2.customer_name
    AND t1.date_code + 1 = t2.date_code
WHERE t2.customer_name IS NULL
GROUP BY t1.customer_name

更新2 つの単一列インデックスの代わりに、これら 2 つのフィールドにまたがる複合インデックスを追加すると、パフォーマンスが大幅に向上します。

CREATE UNIQUE INDEX `UQ_customer_date_code` ON tbl (customer_name, date_code);

160 万件のレコード (21 の date_codes にわたる 100,000 人の顧客) を持つテスト テーブルを使用して、いくつかのテストを行いました。このインデックスを追加すると、クエリ時間が約 80% 短縮されます。NOT EXISTS の代わりに LEFT JOIN を使用すると、クエリ時間が約 15% しか短縮されません。

于 2012-03-11T03:07:20.653 に答える