简体   繁体   中英

MySQL JOIN with multiple tables and SUMS

I am trying to create a query that will take information out of four tables for a billing system that I am creating. I have the following tables:

Table Invoice

InvoiceID (PK)
ClientID
Date
Status
...

Table Client

ClientID (PK)
ClientName
...

Table InvoiceItem

ItemID (PK)
InvoiceID
Amount
...

Table Payments

PaymentID (PK)
InvoiceID
Amount
...

I need to create a query where I can access information from the Invoice table along with the client name, and the sum of all invoice items and payments associated with the invoice.

I have tried the following:

SELECT 
    Invoice.InvoiceID, 
    Invoice.`Date`, 
    Invoice.Terms, 
    Invoice.DateDue, 
    Invoice.Status, 
    Client.ClinicName, 
    SUM(InvoiceItem.Amount), 
    SUM(Payment.PaymentAmount)
FROM Invoice
JOIN (Client, InvoiceItem, Payment) ON
    (Client.ClientID=Invoice.ClientID AND
     InvoiceItem.InvoiceID=Invoice.InvoiceID AND 
     Payment.InvoiceID=Invoice.InvoiceID)

And while this kind-of works, it is multiplying the SUM() by the number of records used to get the sum (ie if there are two payments - 800,400 - It gives me (800+400)*2 -- 2400). I am guessing that there is something with how I am using the join, and I have honestly never had to use join for more than one table, and I would always use GROUP BY, but I can't seem to get that to work correctly.

To make matters worse, I have been lost to the world of vb.net/MSSQL client-side programming for the past several years, so my MySQL is rather rough.

Your problem is that you can't aggregate over two independent tables at once in a single query. However you can do it using subqueries.

SELECT Invoice.InvoiceID, Invoice.`Date`, Invoice.Terms, Invoice.DateDue, Invoice.Status, Client.ClinicName, InvoiceItemSum.SumOfAmount, PaymentSum.SumOfPaymentAmount
  FROM Invoice
  INNER JOIN Client ON Client.ClientID = Invoice.ClientID
  INNER JOIN (
    SELECT InvoiceID, SUM(Amount) AS SumOfAmount
      FROM InvoiceItem
      GROUP BY InvoiceID
  ) InvoiceItemSum ON InvoiceItemSum.InvoiceID = Invoice.InvoiceID
  INNER JOIN (
    SELECT InvoiceID, SUM(PaymentAmount) AS SumOfPaymentAmount
    FROM Payment
    GROUP BY InvoiceID
  ) PaymentSum ON PaymentSum.InvoiceID = Invoice.InvoiceID

Try this:

SELECT
    Invoice.InvoiceID,
    Invoice.`Date`,
    Invoice.Terms,
    Invoice.DateDue,
    Invoice.Status,
    Client.ClinicName,
    SUM(InvoiceItem.Amount),
    SUM(Payment.PaymentAmount)
FROM Invoice 
JOIN Client ON Client.ClientID=Invoice.ClientID
JOIN InvoiceItem ON InvoiceItem.InvoiceID=Invoice.InvoiceID
JOIN Payment ON Payment.InvoiceID=Invoice.InvoiceID
group by 1,2,3,4,5,6;

I did two things to your query:

  1. Created separated joins for each of the child tables
  2. Added a group by , without which the sum won't work correctly (fyi, in all other databases, omitting the group by would actually result in a syntax error)

Here try this one

SELECT  a.InvoiceID,
        a.`Date`,
        a.Terms,
        a.DateDue,
        a.Status,
        b.ClinicName,
        SUM(c.Amount),
        SUM(d.PaymentAmount)
FROM    Invoice a
            INNER JOIN Client b
                on a.ClientID = b.ClientID
            INNER JOIN InvoiceItem c
                ON c.InvoiceID = a.InvoiceID
            INNER JOIN JOIN Payment d
                ON d.InvoiceID = a.InvoiceID
GROUP BY    a.InvoiceID,
            a.`Date`,
            a.Terms,
            a.DateDue,
            a.Status,
            b.ClinicName

can you elaborate more on this?

it is multiplying the SUM() by the number of records used to get the sum (ie if there are two payments - 800,400 - It gives me (800+400)*2 -- 2400)

you can also achive it by "CROSS APPLY"

SELECT Invoice.InvoiceID, Invoice.`Date`, Invoice.Terms, Invoice.DateDue, Invoice.Status, Client.ClinicName, InvoiceItemSum.SumOfAmount, PaymentSum.SumOfPaymentAmount
  FROM Invoice
  INNER JOIN Client ON Client.ClientID = Invoice.ClientID
  CROSS APPLY ( SELECT ISNULL(SUM(Amount),0) AS SumOfAmount 
                                  FROM   InvoiceItem 
                                  WHERE  InvoiceID = Invoice.InvoiceID
                                ) InvoiceItemSum 
  CROSS APPLY ( SELECT ISNULL(SUM(PaymentAmount),0) AS SumOfPaymentAmount 
                                  FROM   Payment 
                                  WHERE  InvoiceID = Invoice.InvoiceID
                                ) PaymentSum 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM