在SQL中跟进购买查询

时间:2012-02-06 09:51:11

标签: sql sql-server-2005 tsql

我有一个会员数据库,我想从中提取购买信息,但我不确定SQL的最佳方式。我们出售订阅,这些订阅是固定时间段进入我们健身房的入场通行证,例如。 3个月。会员购买它们,当它们到期时,它们可能会购买另一个。我们想选择一组成员,例如。那些在不久前购买了3个月通行证的学生,并确定他们的下一次订阅购买是什么,如果有的话。

涉及三个表(包含相关列):

  • SubscriptionTypes(ID,Description,Duration) - 定义可以购买的订阅
  • 订阅(MemberID,SubTypeID,StartDate,EndDate) - 购买实例,将会员与他们随时间购买的订阅类型相关联
  • 会员(ID,类型) - 会员数据,其中Type可以是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 <period start> and <period end>
AND m.Type = 'Student'
AND st.Duration = 3

这给了我一组成员(以及他们去年购买的通行证的实际开始和结束日期)。

但是,如何从这个起点开始,然后在3个月的通行证到期后的期间(比如1个月)中提取这些成员的下一次订阅购买。我可以提出程序方法,例如。迭代上面集合中的每个成员并运行查询,但这不是SQL方式。

任何人都可以给我一些方向吗?我想完成原始套装中的一组成员,他们的第一个购买订阅信息以及他们的第二个(如果有的话)。

2 个答案:

答案 0 :(得分: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'

对于在Student之后或之后开始订阅的每个@PeriodStart成员,这将为您提供每个订阅的行,以及指示订购日期。

所以如果有人花了3个月然后花了1个月,你就得到了

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

在进一步的查询细化或应用程序代码中,您可以根据需要使用序列号。


解释性说明:

概念行为是:

  1. 确定符合WHERE条件的所有购买(即在特定日期之后制作)
  2. 按成员(即PARTITION BY
  3. 对它们进行分组
  4. 在每个成员组中,按日期订购,并记下该组中的位置(即ROW_NUMBER() OVER( ... ORDER BY )
  5. 每次购买都会排一行,其中一列是有序的每个成员组中的位置(这是SubscriptionSequence
  6. 如果您只对进行后续购买的会员感兴趣,可以

    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有两个符合条件的订阅,而成员567有3.只有一个符合条件的订阅的成员不会出现在第二个查询的输出中,因为WHERE子句中的最后一个术语。

答案 1 :(得分:0)

它很大但你可以这样做:

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, <period start>) and dateadd('m', 4, <period end>)
AND m.Type = 'Student'

使用您的选择,您可以进行另一个相等的选择,但内部连接也是如此。通过内部联接,您可以获得要测试的成员以及他们的凭证的结束日期。因此,您可以在外部查询中使用该Enddate。