我有一张付款表,我在下面的sqlfiddle上复制:http://sqlfiddle.com/#!9/8d31c9
我正在尝试提取以下数据:
在我提供的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
答案 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;