Search code examples
mysqlsqljoinoptimizationsubquery

Optimizing MySQL query that includes a repeated subquery


I have the following query that is working perfectly right now, I have been trying to optimize it since I am using the same subquery 4 times. It will be great to come up with a better/smarter solution. Thank you

Here is the query:

  select 
     invoices.invoice_id
    ,invoices.invoice_amount
    ,(
      select SUM(invoice_payment_amount) as total
      FROM invoice_payments
      where invoice_payment_invoice_id = invoices.invoice_id
     ) as payments
    ,round((invoices.invoice_amount-(
      select SUM(invoice_payment_amount) as total
      FROM invoice_payments
      where invoice_payment_invoice_id = invoices.invoice_id
     )),2) as balance 
  from invoices
  where (
    round((invoices.invoice_amount - 
         (select SUM(invoice_payment_amount) as total
          FROM invoice_payments
          where invoice_payment_invoice_id = invoices.invoice_id)
          ),2)
      ) > 0 
    or (
    round((invoices.invoice_amount - 
         (select SUM(invoice_payment_amount) as total
          FROM invoice_payments
          where invoice_payment_invoice_id = invoices.invoice_id)
          ),2)
      ) IS NULL
  order by balance

SQL Fiddle: http://sqlfiddle.com/#!9/aecea/1


Solution

  • Just use a subquery:

    select i.invoice_id, i.invoice_amount, i.payments,
           round((i.invoice_amount- i.payments), 2) as balance
    from (select i.*, 
                 (select sum(ip.invoice_payment_amount)
                  from invoice_payments ip
                  where ip.invoice_payment_invoice_id = i.invoice_id
                 ) as payments
          from invoices i
         ) i
    where round((i.invoice_amount- i.payments), 2) > 0 or
          round((i.invoice_amount- i.payments), 2) is null
    order by balance;
    

    For better performance, you want an index on invoice_payments(invoice_payment_invoice_id, invoice_payment_amount).