Re: Can pure SQL provide AR/AP reports?

From: John Gilson <jag_at_acm.org>
Date: Fri, 20 Jun 2003 21:21:17 GMT
Message-ID: <hVKIa.162798$h42.41804_at_twister.nyc.rr.com>


"CN" <cnliou9_at_fastmail.fm> wrote in message news:8566aead.0306200317.39a6a6eb_at_posting.google.com...
> I have 2 tables, owe and pay.
>
> CREATE TABLE owe (
> PRIMARY KEY (customer,DueDate),
> customer CHAR(10),
> DueDate DATE,
> OweAmount INTEGER
> );
>
> CREATE TABLE pay (
> PRIMARY KEY (customer,PayDate),
> customer CHAR(10),
> PayDate DATE,
> PayAmount INTEGER
> );
>
> select * from owe order by DueDate;
> customer | DueDate | OweAmount
> ------------+------------+-----------
> a | 2003-01-01 | 100
> a | 2003-02-01 | 200
> a | 2003-03-01 | 300
> a | 2003-04-01 | 400
> a | 2003-05-01 | 500
> a | 2003-06-01 | 600
> (6 rows)
>
> select * from pay order by PayDate;
> customer | PayDate | PayAmount
> ------------+------------+-----------
> a | 2003-01-01 | 90
> a | 2003-02-05 | 160
> a | 2003-02-27 | 250
> a | 2003-02-28 | 100
> a | 2003-04-02 | 450
> (5 rows)
>
> As we can see, this is a payment term where installment is allowed.
> Table "owe" is designed to accomodiate unlimited number of customers
> and due dates, so is table "pay".
> Customer "a" is unlikely to make payment in time before deadlines.
>
> I need a SQL to report the un-paid detail:
> customer | DueDate | OweAmount | PayAmount
> ------------+------------+-----------+-----------
> a | 2003-05-01 | 500 | 50
> a | 2003-06-01 | 600 | 0
>
> This report assumes that customers always make their payments to first
> balance the oldest due amounts. That is said, it is NOT allowed for
> customer "a" to:
> pay $600 to balance the amount due on 2003-06-01 while refuse to pay
> $100 due on 2003-01-01.
>
> I am using PostgreSQL. Complicate SELECT clauses can be used.
> Please help! TIA
> CN

The following works under MS SQL Server and is completely Standard SQL. Hopefully you have similar success under PostgreSQL. By the way, thanks for the DDL and sample data.

SELECT O.customer,

               O.duedate,
               O.oweamount,
               CASE WHEN PaidTotal.total >= OwedToDate.prevtotal
                          THEN PaidTotal.total - OwedToDate.prevtotal
                          ELSE 0
               END AS payamount
FROM (SELECT C.customer, COALESCE(SUM(P.payamount), 0)
              FROM (SELECT DISTINCT customer
                           FROM Owe) AS C(customer)
                          LEFT OUTER JOIN
                          Pay AS P
                          ON C.customer = P.customer
              GROUP BY C.customer) AS PaidTotal(customer, total)
            INNER JOIN
            (SELECT O1.customer,
                             O1.duedate,
                             SUM(O2.oweamount),
                             SUM(O2.oweamount) - O1.oweamount
             FROM Owe AS O1
                         INNER JOIN
                         Owe AS O2
                         ON O1.customer = O2.customer AND
                                O2.duedate <= O1.duedate
             GROUP BY O1.customer, O1.duedate, O1.oweamount)
            AS OwedToDate(customer, duedate, total, prevtotal)
            ON OwedToDate.customer = PaidTotal.customer
            INNER JOIN
            Owe AS O
            ON O.customer = OwedToDate.customer AND
                   O.customer = PaidTotal.customer AND
                   O.duedate = OwedToDate.duedate AND
                   PaidTotal.total < OwedToDate.total
ORDER BY O.customer, O.duedate

Note that this solution works even if no payments have been received from a customer but yet money is owed (imagine that!). For example, if customer "a" owes as described above but has made no payments, that is, there are no entries for this customer in the Pay table, the result is

customer duedate oweamount payamount

a          2003-01-01 00:00:00.000 100 0
a          2003-02-01 00:00:00.000 200 0
a          2003-03-01 00:00:00.000 300 0
a          2003-04-01 00:00:00.000 400 0
a          2003-05-01 00:00:00.000 500 0
a          2003-06-01 00:00:00.000 600 0

Regards,
jag Received on Fri Jun 20 2003 - 23:21:17 CEST

Original text of this message