By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,854 Members | 2,015 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,854 IT Pros & Developers. It's quick & easy.

Calculating totals from two tables

P: n/a
Hopefully someone can help me create a query that I'm having some
trouble with.

I have three tables: invoices, invoicedetails, invoicepayments

The fields are:

invoices
--------
InvoiceNo
InvoiceDate
CompanyNo

invoicedetails
--------------
InvoiceNo
ProductNo
Quantity
UnitPrice

invoicepayments
---------------
InvoiceNo
PaymentDate
PaymentAmount

For each row in invoices there will be 0 or more rows in
invoicedetails and invoicepayments, with the InvoiceNo field linking
everything together (i.e. one to many relationship between invoices
and invoicedetails and invoicepayments).

I need a query that will give me a list of invoices that still have
money outstanding on them.

To manually do this I would loop through the invoices table and for
each InvoiceNo I would gather all the matching rows in invoicedetails
and invoicepayments. To get the invoice total I would multiply
Quantity by UnitPrice for each invoicedetails row. To get the total
paid I would add up the PaymentAmount. Then I'd compare the invoice
total and the payment total and if the payment total was less than the
invoice total I'd know that there was still some money outstanding on
that invoice.

Now, how do I write a single query to do this? I using MySQL 4.0.20
(unfortunately because I don't control the server I can't upgrade to a
version of MySQL that support subqueries). I'm guessing I'll need to
use the SUM() function to add things up, and GROUP BY to group the
invoicedetails and invoicepayments so I only get one row per invoice.

I can get a total for each invoice by using the following query:

SELECT invoices.InvoiceNo, SUM(Quantity * UnitPrice) AS InvTotal
FROM invoices, invoicedetails
WHERE invoices.InvoiceNo = invoicedetails.InvoiceNo
GROUP BY invoices.InvoiceNo

However I'm at a loss as to how I would modify this query to also
total up the invoicepayments to give me a PaymentsTotal and then
calculate the difference between the InvTotal and the PaymentsTotal to
figure out if there is still money outstanding.

Can anyone help me out or point me in the right direction?
Jul 20 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
The Bit Bandit wrote:
Can anyone help me out or point me in the right direction?


I think this might help. One part I'm unsure of (without testing it) is
whether one can use a derived column name in the HAVING clause.

SELECT i.InvoiceNo, SUM(d.Quantity * d.UnitPrice) AS InvTotal,
SUM(d.Quantity * d.UnitPrice) - SUM(p.PaymentAmount) AS
InvRemainingBalance
FROM invoices i INNER JOIN invoicedetails d ON (i.InvoiceNo = d.InvoiceNo)
LEFT OUTER JOIN invoicepayments p ON (i.InvoiceNo = p.InvoiceNo)
HAVING InvRemainingBalance > 0
GROUP BY i.InvoiceNo

Regards,
Bill K.
Jul 20 '05 #2

P: n/a
Many thanks for your help, Bill. Your advice is greatfully received!

It looks like you can't use a derived column name in the HAVING
clause. When I tried it I got the following error:

#1064 - You have an error in your SQL syntax near 'GROUP BY
i.InvoiceNo'

I'm assuming the error message is referring to the HAVING clause,
which is immediately before the GROUP BY clause.

I tried simplifying the query to see just the totals (i.e. not working
out the difference to get the amount outstanding) and the query looks
like this:

SELECT i.InvoiceNo, SUM(d.Quantity * d.UnitPrice) AS InvTotal,
SUM(p.PaymentAmount) AS InvRemainingBalance
FROM invoices i
INNER JOIN invoicedetails d ON (i.InvoiceNo = d.InvoiceNo)
LEFT OUTER JOIN invoicepayments p ON (i.InvoiceNo = p.InvoiceNo)
GROUP BY i.InvoiceNo

I notice that for this query the total payments is being calculated
incorrectly. For example I have one invoice with 11 detail lines that
total up to 5136.86. This invoice has a single payment of 5136.86,
but the query is telling me that the total payments for this invoice
is 56505.46 (which just happens to be the total for the invoice
multiplied by the number of detail lines).

It's as if MySQL is expecting the number of invoicepayments records to
be the same as the number of invoicedetails for any particular
invoice, and because it isn't it's repeating the amounts.

Any ideas on how to fix this?
Bill Karwin <bi**@karwin.com> wrote in message news:<cl*********@enews4.newsguy.com>...
The Bit Bandit wrote:
Can anyone help me out or point me in the right direction?


I think this might help. One part I'm unsure of (without testing it) is
whether one can use a derived column name in the HAVING clause.

SELECT i.InvoiceNo, SUM(d.Quantity * d.UnitPrice) AS InvTotal,
SUM(d.Quantity * d.UnitPrice) - SUM(p.PaymentAmount) AS
InvRemainingBalance
FROM invoices i INNER JOIN invoicedetails d ON (i.InvoiceNo = d.InvoiceNo)
LEFT OUTER JOIN invoicepayments p ON (i.InvoiceNo = p.InvoiceNo)
HAVING InvRemainingBalance > 0
GROUP BY i.InvoiceNo

Regards,
Bill K.

Jul 20 '05 #3

P: n/a
The Bit Bandit wrote:
It's as if MySQL is expecting the number of invoicepayments records to
be the same as the number of invoicedetails for any particular
invoice, and because it isn't it's repeating the amounts.
Yes, I see why it's doing that. The inner join between invoices and
invoicedetails is a multi-line result set, and for each of those lines,
it repeats the invoicepayment. Mea culpa! I should have noticed this
when I gave the suggested query.
Any ideas on how to fix this?


Try this:
SELECT i.InvoiceNo, SUM(d.Quantity * d.UnitPrice) AS InvTotal,
SUM(p.PaymentAmount) / COUNT(d.InvoiceNo) AS InvRemainingBalance
....

But this seems like a pretty ugly hack to me, even though it may give
the correct result. It's not very maintainable!

The other solution I can think of is that you'd have to calculate the
InvTotal and InvRemainingBalance in separate queries. That would
require recombining the results in your application, but it would be
much clearer code and more maintainable.

You might have more options when you can use MySQL 4.1 with subqueries.

Regards,
Bill K.
Jul 20 '05 #4

P: n/a
Thanks again, Bill, for your great help.

I'm thinking that it may well be easier to add a new field to the
invoices table that flags whether the invoice has been paid in full or
not. Then in my app when payments are being entered I can easily
figure out if the invoice has been fully paid for and if so set the
flag. Then it's just a simple matter of selecting the invoices that
don't have the flag set.

I know this kind of goes against data normalisation rules, but it will
certainly be easier!

Thank you very much for all your help, I've certainly learned a thing
or two about MySQL.

Bill Karwin <bi**@karwin.com> wrote in message news:<cl*********@enews3.newsguy.com>...
The Bit Bandit wrote:
It's as if MySQL is expecting the number of invoicepayments records to
be the same as the number of invoicedetails for any particular
invoice, and because it isn't it's repeating the amounts.


Yes, I see why it's doing that. The inner join between invoices and
invoicedetails is a multi-line result set, and for each of those lines,
it repeats the invoicepayment. Mea culpa! I should have noticed this
when I gave the suggested query.
Any ideas on how to fix this?


Try this:
SELECT i.InvoiceNo, SUM(d.Quantity * d.UnitPrice) AS InvTotal,
SUM(p.PaymentAmount) / COUNT(d.InvoiceNo) AS InvRemainingBalance
...

But this seems like a pretty ugly hack to me, even though it may give
the correct result. It's not very maintainable!

The other solution I can think of is that you'd have to calculate the
InvTotal and InvRemainingBalance in separate queries. That would
require recombining the results in your application, but it would be
much clearer code and more maintainable.

You might have more options when you can use MySQL 4.1 with subqueries.

Regards,
Bill K.

Jul 20 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.