SQLで購入クエリをフォローアップする

私は購買情報を抽出したいメンバーシップデータベースを持っていますが、私はSQLの中で最善の方法は不明です。私たちは定期購読を販売しています。定期購読は一定期間、ジムへの入場券です。 3ヶ月。メンバーはそれらを購入し、期限が切れると別のメンバーを買うかもしれません。メンバーのグループを選択したいと思います。しばらく前に3か月のパスを購入した学生は、次回の購読購入があった場合はそれを決定します。

関連する列を持つ3つのテーブルがあります。

  • SubscriptionTypes(ID、Description、Duration) - 購読可能な購読の種類を定義します。
  • サブスクリプション(MemberID、SubTypeID、StartDate、EndDate) - 購入のインスタンス、時間の経過とともに購入したサブスクリプションタイプのメンバーにリンクします。
  • メンバー(ID、タイプ) - 会員データ(Student、Standard、Pensionerの場合)

だから、昨年の今年に3ヶ月購読したメンバーのIDを知りたければ、私は次のようなものを使うことができました:

SELECT MemberID, StartDate, EndDate
FROM Subscriptions s
INNER JOIN Members m
ON s.MemberID = m.ID
INNER JOIN SubscriptionTypes st
ON s.SubTypeID = st.ID
WHERE s.StartDate BETWEEN  and 
AND m.Type = 'Student'
AND st.Duration = 3

これにより、メンバーの集合(そして昨年購入したパスの実際の開始日と終了日)がわかります。

しかし、どのように私はこの出発点から出発して、3ヶ月の有効期限が切れた後の期間(例えば1ヶ月)にこれらのメンバーの次の購読購入を抽出するのですか? 手続き型メソッドを思いつくことができます。上のセットの各メンバーを繰り返してクエリを実行しますが、これはSQLの方法ではありません。

誰か私にある方向を与えることができますか?私は元のセット、彼らの最初の購読予約情報とその2番目の(もしあれば)メンバーのセットで終了したいと思います。

3

2 答え

SQL Server 2005を使用しているので、 ROW_NUMBER をご利用ください。私は何かのように始めることを提案するでしょう

SELECT MemberID, StartDate, EndDate,
    ROW_NUMBER() OVER(PARTITION BY MemberID ORDER BY s.StartDate ASC) 
        AS SubscriptionSequence
FROM Subscriptions s
INNER JOIN Members m ON s.MemberID = m.ID
INNER JOIN SubscriptionTypes st ON s.SubTypeID = st.ID
WHERE @PeriodStart <= s.StartDate
AND m.Type = 'Student'

これは、 @PeriodStart 以降で開始するサブスクリプションを持つ各 Student メンバー、 Every every サブスクリプションの行、日付の順序を示すシーケンス番号。

だから誰かが3ヶ月、1ヶ月かかると、あなたは

TheMemberId    Jul 1 2011    Sep 30 2011     1
TheMemberId    Oct 1 2011    Oct 31 2011     2

さらにクエリの洗練化またはアプリケーションコードのいずれかで、必要に応じてシーケンス番号を使用できます。


解説:

概念的な動作は次のとおりです。

  1. WHERE の条件を満たす(つまり、特定の日付以降に行われた)すべての購入を特定する
  2. メンバー別にグループ化する( PARTITION BY
  3. 各メンバーのグループ内で、日付順に購入を注文し、そのグループ内の位置をメモします(これは ROW_NUMBER()OVER(... ORDER BY)です)。
  4. 購入ごとに行を発行します。列の1つは、注文されたメンバーごとのグループ内の位置です(これは SubscriptionSequence

フォローアップ購入を行ったメンバーのみに興味がある場合は、

SELECT MemberID, StartDate, EndDate,
    ROW_NUMBER() OVER(PARTITION BY MemberID ORDER BY s.StartDate ASC) 
        AS SubscriptionSequence,
    (SELECT COUNT(*) FROM Subscriptions ss 
                     WHERE @PeriodStart <= ss.StartDate
                     AND ss.MemberID = m.ID) AS SubscriptionCount
FROM Subscriptions s
INNER JOIN Members m ON s.MemberID = m.ID
INNER JOIN SubscriptionTypes st ON s.SubTypeID = st.ID
WHERE @PeriodStart <= s.StartDate
AND m.Type = 'Student'
AND SubscriptionCount >= 2

私は相関サブクエリを使用して、各行にその行で参照されているメンバが行った適格なサブスクリプションの数をカウントする列を含めました。

メンバーID 234および567の出力例:

234   Jul 1 2011    Sep 30 2011     1     2
234   Oct 1 2011    Oct 31 2011     2     2
567   Jul 1 2011    Sep 30 2011     1     3
567   Oct 1 2011    Oct 31 2011     2     3
567   Dec 1 2011    Dec 31 2011     3     3

ここでメンバー234は2つの適格なサブスクリプションを持っていましたが、メンバー567は3でした。 WHERE 節の最後の項のために、1つの適格サブスクリプションしか持たないメンバーはこの2番目のクエリーの出力に表示されません。

2
追加された
それを少し拡大した
追加された 著者 AakashM,
答えをありがとう。私はまだそれの周りに私の頭を取得しようとしています。学生が3ヶ月間のパスを購入した場合、その行(つまり、2回目の購入なし)があるかどうかを教えてください。
追加された 著者 dave,

それは大きいですが、あなたは次のようなことをすることができます:

SELECT m.MemberID, s.StartDate, s.EndDate
FROM Subscriptions s
INNER JOIN Members m
ON s.MemberID = m.ID
INNER JOIN SubscriptionTypes st
ON s.SubTypeID = st.ID

INNER JOIN (SELECT m.MemberID, s.EndDate
FROM Subscriptions s
INNER JOIN Members m
ON s.MemberID = m.ID
INNER JOIN SubscriptionTypes st
ON s.SubTypeID = st.ID
WHERE s.StartDate BETWEEN a.EndDate and dateadd('m', 1, a.EndDate)
AND m.Type = 'Student'
AND st.Duration = 3) a on a.MemberID = m.MemberID

WHERE s.StartDate BETWEEN dateadd('m', 4, ) and dateadd('m', 4, )
AND m.Type = 'Student'

あなたの選択で、あなたは別の等しい選択を行いますが、内部結合があります。インナー・ジョイントでは、テストしたいメンバーとバウチャーの終了日を取得します。したがって、外部クエリでそのEnddateを使用することができます。

0
追加された
a)はい、私は編集しました。 b)内部クエリ(私はそれにエイリアスを作った)c)はい、2番目を作ったものだけを選択します。内部クエリ(エイリアスa)はパスを購入したメンバを選択し、外部クエリはそれらのメンバから別のものを購入したメンバを選択します
追加された 著者 aF.,
ご回答有難うございます。 2つの質問:(a)1行目のn.MemberIDを参照してください。それはm.MemberIDですか? (b)あなたは "a"という2つの列を参照します。接頭辞として "a"はどこに定義されていますか? (c)これは、3ヶ月間のパスを購入する学生は除外しますが、それ以外は何もしません。 2回目の購入者を選択するだけですか?
追加された 著者 dave,