我有一个会员数据库,我想从中提取购买信息,但我不确定SQL的最佳方式。我们出售订阅,这些订阅是固定时间段进入我们健身房的入场通行证,例如。 3个月。会员购买它们,当它们到期时,它们可能会购买另一个。我们想选择一组成员,例如。那些在不久前购买了3个月通行证的学生,并确定他们的下一次订阅购买是什么,如果有的话。
涉及三个表(包含相关列):
因此,如果我想确定去年这个时候购买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方式。
任何人都可以给我一些方向吗?我想完成原始套装中的一组成员,他们的第一个购买订阅信息以及他们的第二个(如果有的话)。
答案 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
在进一步的查询细化或应用程序代码中,您可以根据需要使用序列号。
解释性说明:
概念行为是:
WHERE
条件的所有购买(即在特定日期之后制作)PARTITION BY
)ROW_NUMBER() OVER( ... ORDER BY )
)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有两个符合条件的订阅,而成员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。