获取自己重新订阅的客户

时间:2015-08-27 14:43:47

标签: mysql join

我有一张付款表,我在下面的sqlfiddle上复制:http://sqlfiddle.com/#!9/8d31c9

我正在尝试提取以下数据:

  • 在2015年获取自行重新订阅的客户(即“类型”等于“SUBSCRIPTION”和“advisor_create”等于0)。要被视为RE订户,客户应至少拥有一个使用“SUBSCRIPTION”类型付款(年份和顾问创建对此次付款并不重要)
  • 一旦这个基本查询正在运行,我将有更多数据要提取,比如知道这些客户是否重新订阅了不同的优惠或同一个,如果他们的新订阅比前一个更便宜或更昂贵。 / LI>

在我提供的sqlfiddle示例数据中,此查询应返回客户#2(由于付款ID#4)和#5(由于付款ID#8)。

现在,我写了以下查询:

SELECT p.id, p.customer_id, p.date, p.type, p.offer, p.value
FROM payments p
WHERE p.type = "SUBSCRIPTION"
AND YEAR(p.date) = 2015
AND advisor_create = 0

但我不知道如何将此查询与支付表自我加入,以检查过去是否为这些客户发生了订阅。 任何帮助将不胜感激。

更新#1:

根据下面的答案,我尝试使用我的问题的第二部分并尝试以下查询:

SELECT p.customer_id, P.offer, p.value, previous_payments.offer AS previous_offer, previous_payments.value AS previous_value
FROM payments p 
JOIN payments previous_payments ON ( 
    previous_payments.customer_id = p.customer_id 
    AND previous_payments.date < p.date 
    AND previous_payments.type = 'SUBSCRIPTION' 
) 
WHERE p.type = 'SUBSCRIPTION' 
AND p.advisor_create = 0 
AND YEAR(p.date) = 2015
GROUP BY p.customer_id 

客户#5的数据错误,previous_offer和之前的值应该等于21和14,因为这是该客户的最新以前的订阅。如何使用最新的先前订阅进行连接?

更新#2

根据我的评论指出最终结果集中的错误,我修复了您的最新查询(具有临时联接表的那个,请参阅您的编辑2部分),如下所示:

SELECT p.customer_id, p.offer, p.value, previous_payments.offer AS previous_offer, previous_payments.value AS previous_value
FROM payments p
JOIN (
    SELECT *
    FROM payments
    JOIN ( select customer_id, max(date) as date from payments p1
        where date < ( select max(date) from payments p2 where p1.customer_id = p2.customer_id and p2.advisor_create = 0 )
    group by customer_id ) p2 USING (customer_id, date)
    WHERE type = 'SUBSCRIPTION'
) previous_payments ON previous_payments.customer_id = p.customer_id AND previous_payments.date < p.date
WHERE p.type = 'SUBSCRIPTION'
AND p.advisor_create = 0
AND YEAR(p.date) = 2015;

这是对的吗? 刚刚在子子查询中添加了and p2.advisor_create = 0

1 个答案:

答案 0 :(得分:1)

  

如何使用付款表自我加入此查询

这是一种方法:

SELECT p.customer_id
FROM payments p
JOIN payments previous_payments ON (
    previous_payments.customer_id = p.customer_id 
    AND previous_payments.date < p.date 
    AND previous_payments.type = 'SUBSCRIPTION'
)
WHERE p.type = 'SUBSCRIPTION'
AND p.advisor_create = 0
AND YEAR(p.date) = 2015
GROUP BY p.customer_id;

但还有很多其他选择。

修改

好的,显然这只能解决你问题的一半。您使用上述查询未获得正确的先前付款的原因是GROUP BY。所以我们需要删除它。让我们分解问题。

您需要知道之前的付款。这是倒数第二次付款。

以下是获取特定客户上次付款日期的方法:

SELECT MAX(date) FROM payments WHERE customer_id = X;

以下是如何获取给定客户的倒数第二次付款的日期:

SELECT MAX(date) FROM payments p1
WHERE p1.date < ( SELECT MAX(date) FROM payments p2 WHERE p1.customer_id = p2.customer_id )
AND p1.customer_id = X 

现在我们可以将此子句作为where子句添加到相关子查询中的原始查询中,以便仅保留最后一次付款,从而删除该组。

SELECT p.customer_id, p.offer, p.value, previous_payments.offer AS previous_offer, previous_payments.value AS previous_value
FROM payments p
JOIN payments previous_payments ON (
    previous_payments.customer_id = p.customer_id 
    AND previous_payments.date < p.date 
    AND previous_payments.type = 'SUBSCRIPTION'
)
WHERE p.type = 'SUBSCRIPTION'
AND p.advisor_create = 0
AND YEAR(p.date) = 2015
AND previous_payments.date = (
    SELECT MAX(date) FROM payments p1
    WHERE date < ( SELECT MAX(date) FROM payments p2 WHERE p1.customer_id = p2.customer_id )
    AND p1.customer_id = p.customer_id
);

返回:

+-------------+-------+-------+----------------+----------------+
| customer_id | offer | value | previous_offer | previous_value |
+-------------+-------+-------+----------------+----------------+
|           2 |    23 | 11.00 |             21 |          12.00 |
|           5 |    21 | 15.00 |             21 |          14.00 |
+-------------+-------+-------+----------------+----------------+

编辑2

这是另一种编写相同查询的方法,没有相关的子查询,而是使用临时连接表(因此它可能更快):

SELECT p.customer_id, p.offer, p.value, previous_payments.offer AS previous_offer, previous_payments.value AS previous_value
FROM payments p
JOIN (
    SELECT *
    FROM payments
    JOIN ( select customer_id, max(date) as date from payments p1
        where date < ( select max(date) from payments p2 where p1.customer_id = p2.customer_id )
    group by customer_id ) p2 USING (customer_id, date)
    WHERE type = 'SUBSCRIPTION'
) previous_payments ON previous_payments.customer_id = p.customer_id AND previous_payments.date < p.date
WHERE p.type = 'SUBSCRIPTION'
AND p.advisor_create = 0
AND YEAR(p.date) = 2015;