2011-10-17 40 views
0

我试图产生debitors的年龄平衡,但我使用MySQL SUM时,我必须采取平衡考虑在内有touble。Mysql的SUM - 如何避免和同样的东西多次

我可以得到客户的当前余额:

SELECT SUM(balance) FROM `transaction` WHERE customer_id = 1 

起初,当我希望得到一个旧的平衡 - 即。平衡的样子2011-08-31我认为以下是不够的:

SELECT SUM(balance) FROM `transaction` WHERE customer_id = 1 AND posted <= '2011-08-31' 

但上面并没有采取自2011-09-01已发生到现在考虑任何平衡的历史。我已经储存了所有历史的平衡在一个表中。所以,如果一个客户(部分)埋单2011-09-06那么表将类似于以下内容:

交易:

id | text | amount | balance | posted 
1 | Invoice | 100.00 | 20.00 | 2011-08-14 
2 | Payment | 80.00 | 0.00 | 2011-09-06 

平衡历史:

id | source | destination | amount | created 
1 |  1 |   2 | 80.00 | 2011-09-06 

我想我用下面的查询解决它:

SELECT customer_id, SUM(balance)+SUM(IFNULL(bh_source.amount, 0))-SUM(IFNULL(bh_destination.amount, 0)) AS `current_balance` 
FROM `transaction` 
LEFT JOIN balancehistory AS bh_source ON `transaction`.id = bh_source.source AND DATE(bh_source.created) > "2011-08-31" 
LEFT JOIN balancehistory AS bh_destination ON `transaction`.id = bh_destination.destination AND DATE(bh_destination.created) > "2011-08-31" 
WHERE posted <= "2011-08-31" 
GROUP BY customer_id 

但当平衡历史BECO mes更复杂,即。像下面 - 它失败:

交易:

id | text    | amount | balance | posted 
1 | Invoice   | 100.00 | 0.00 | 2011-08-14 
2 | Payment   | -80.00 | 0.00 | 2011-09-06 
3 | Payment cancelled | 80.00 | 0.00 | 2011-09-08 
4 | VISA    | -100.00 | 0.00 | 2011-10-10 

平衡历史:

id | source | destination | amount | created 
1 |  1 |   2 | 80.00 | 2011-09-06 
2 |  2 |   1 | -80.00 | 2011-09-08 
3 |  3 |   2 | 80.00 | 2011-09-08 
4 |  1 |   4 | -100.00 | 2011-10-10 

我一直在敲打我的头靠在墙上,现在很长一段时间,希望你们有一些建议。表结构锁定,如果需要的话也可以改变。

谢谢。

更新:

现在我看到,我已经简化我的问题太多 - 但无论如何感谢汤姆。 我不(仅)感兴趣的当前总,而是我要根据他们的到期日金额群。我试图创建一个表,该表显示多少了,由于付款。 IE浏览器。 0-30之间的天,30-90天等。:

年龄平衡(多个SQL使用以下数据不同的基准日期的结果):

reference | before due | 0-30 days | 30-90 days 
2011-08-31 |  233.79 |  0.00 |  0.00 
2011-09-02 |  0.00 |  0.00 |  0.00 
2011-09-07 |  0.00 | 233.79 |  0.00 
2011-10-18 |  100.00 |  0.00 |  233.79 
2011-10-25 |  0.00 | 100.00 |  233.79 
2011-10-28 |  0.00 |  0.00 |  0.00 

交易:

id | customer_id | text    | amount | balance | posted  | due 
1 |   1 | Invoice 1  | 233.79 | 0.00 | 2011-08-17 | 2011-09-01 
2 |   1 | Payment 1  | -233.79 | 0.00 | 2011-09-01 | 2011-09-01 
3 |   1 | Payment rejected | 233.79 | 0.00 | 2011-09-06 | 2011-09-06 
4 |   1 | Reminder   | 100.00 | 0.00 | 2011-09-14 | 2011-09-23 
5 |   1 | Payment 2  | -333.79 | 0.00 | 2011-09-23 | 2011-09-23 

余额历史:

id | source | destination | amount | created 
1 |  1 |   2 | 233.79 | 2011-09-05 
2 |  2 |   1 | 233.79 | 2011-09-09 
3 |  3 |   2 | 233.79 | 2011-09-09 
4 |  1 |   5 | 233.79 | 2011-10-26 
5 |  4 |   5 | 100.00 | 2011-10-26 

下面是一个我认为SQL的示例会查找特定日期的年龄平衡:

SELECT SUM(IF("2011-08-31" <= due, balance, 0)) 
    + SUM(IF("2011-08-31" <= due, IFNULL(bh_source.amount, 0), 0)) 
    - SUM(IF("2011-08-31" <= due, IFNULL(bh_destination.amount, 0), 0)) AS before_due, 
     SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 0 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 30 DAY)), balance, 0)) 
    + SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 0 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 30 DAY)), IFNULL(bh_source.amount, 0), 0)) 
    - SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 0 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 30 DAY)), IFNULL(bh_destination.amount, 0), 0)) AS 0_30_days, 
     SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 30 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 90 DAY)), balance, 0)) 
    + SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 30 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 90 DAY)), IFNULL(bh_source.amount, 0), 0)) 
    - SUM(IF("2011-08-31" > DATE(ADDDATE(due, INTERVAL 30 DAY)) AND 
       "2011-08-31" <= DATE(ADDDATE(due, INTERVAL 90 DAY)), IFNULL(bh_destination.amount, 0), 0)) AS 30_90_days 
FROM `transaction` 
LEFT JOIN balancehistory AS bh_source ON `transaction`.id = bh_source.source AND DATE(bh_source.created) > "2011-08-31" 
LEFT JOIN balancehistory AS bh_destination ON `transaction`.id = bh_destination.destination AND DATE(bh_destination.created) > "2011-08-31" 
WHERE posted <= "2011-08-31" 
GROUP BY customer_id 

但它不能按预期工作。任何帮助/建议,将不胜感激。

回答

0

如果将发票和支付交易分成两个单独的表格,您可能会有更多乐趣。例如:

invoice 
id | customer_id | invoice_description | amount | postedOn 
1 |  1  | Services Invoice  | 100.00 | 2011-08-14 12:35:01 

payment 
id | customer_id | invoice_id | payment_type  | amount | madeOn 
1 |  1  |  1  | Payment    | -80.00 | 2011-09-08 08:09:12 
1 |  1  |  1  | Payment Cancelled | 80.00 | 2011-09-08 08:12:34 
1 |  1  |  1  | VISA Payment  | -100.00 | 2011-10-10 17:22:54 

那么你应该能够在任何时候获得及时为特定客户的当前余额通过获取及时发给他们到这一点,所有发票之和减去收到的付款在相同的发票时间点之前。因此:

select customer_id,sum(invoice_balance) as totalBalance 
from 
(
select i.customer_id, i.id as invoice_id, 
i.amount - sum(ifnull(p.amount,0)) as invoice_balance 
from invoice i 
left join (select p.invoice_id,p.amount from payment where p.madeOn > '2011-09-01') p 
on p.invoice_id = i.id 
where i.postedOn > '2011-09-01' 
group by i.customer_id, i.id, i.amount 
) t group by customer_id; 

我已经省略CUSTOMER_ID联接的目的,因为我想这是可能的(但不太可能)由不同的客户为之发票在最初发布的客户进行支付。进一步考虑它可能需要将支付表上的payment_type列标准化为paymentType表或类似的东西。

+0

根据我最初的问题,你的回答是正确的,但我意识到我的问题是错误的:-S – Jacob