从依赖于连接表的子查询中选择求和值

时间:2012-06-19 15:46:55

标签: mysql sql optimization join subquery

所以我很幸运能够为我们的应用程序优化查询,这对于我们获得的数据来说花费的时间太长了。我们正在寻找的数据并不复杂,但是糟糕的数据库设计使它变得更加困难(这很棒,因为我是一年前设计它的人)。

一般的想法是我们试图计算每个客户的总销售额(他们购买增加余额的东西)和总支付(他们为余额支付的钱)。

表格:

客户

  • ID
  • 公司

销售(发票)

  • ID
  • CUSTOMER_ID

付款(account_payments)

  • ID
  • CUSTOMER_ID
  • transaction_id(指向invoice_transactions的链接)

交易(invoice_transactions)

  • ID
  • invoice_id(发票链接,付款时为null)
  • 金额

如果用户进行了促销,则该信息会记录在invoicesinvoice_transactions中,其中invoice_transactions具有包含customer_id的发票记录的invoice_id。

如果用户进行付款,则信息将记录在account_paymentsinvoice_transactions中,invoice_transaction的invoice_id为NULL,account_payments包含transaction_id以及customer_id。

我知道,这太可怕了......我以为我很聪明!好吧,我认为问题通过了,并提出了一个不错的解决方案:

SELECT SQL_NO_CACHE
    c.company,
    (SELECT SUM(amount) FROM sales),
    (SELECT SUM(amount) FROM payments)
FROM customers c
JOIN invoices i ON i.customer_id = c.id
JOIN invoice_transactions sales ON i.invoice_id = sales.id
JOIN account_payments ap ON ap.customer_id = c.id
JOIN invoice_transactions payments ON ap.transaction_id = payments.id

除了给我一个错误之外什么都没做“#1146 - 表'db.sales'不存在”。我猜它与连接之前读取的子查询有关,但老实说我不知道​​。不幸的是,我不知道另一种解决这个问题的方法......如果有人能帮我一把,我们非常感激!

2 个答案:

答案 0 :(得分:2)

我认为最好的方法是将销售和付款元素分成子查询,您当前的方法是在进行汇总之前将所有付款与所有发票交叉加入。

SELECT  c.ID, 
        c.Company, 
        COALESCE(Sales.Amount, 0) AS Sales, 
        COALESCE(Payments.Amount, 0) AS Payments
FROM    Customers c
        LEFT JOIN
        (   SELECT  Customer_ID, SUM(Amount) AS Amount
            FROM    Invoices
                    INNER JOIN invoice_transactions
                        ON Invoice_ID = Invoices.ID
            GROUP BY Customer_ID
        ) As Sales
            ON Sales.Customer_ID = c.ID
        LEFT JOIN
        (   SELECT  Customer_ID, SUM(Amount) AS Amount
            FROM    Account_Payments 
                    INNER JOIN invoice_transactions tr
                        ON tr.ID = Transaction_ID
            GROUP BY Customer_ID
        ) AS Payments
            ON Payments.Customer_ID = c.ID;

这将包括没有发票且没有付款的客户。您可以将左连接更改为内连接以对其进行操作。

<强> Working Example on SQL Fiddle

答案 1 :(得分:1)

您的查询没有意义。

完成所有加入之后,为什么不使用“from”子句中的表:

SELECT c.company, SUM(sales.amount),  SUM(payments.amount)
FROM customers c JOIN invoices i ON i.customer_id = c.id JOIN
     invoice_transactions sales ON i.invoice_id = sales.id JOIN
     account_payments ap ON ap.customer_id = c.id JOIN
     invoice_transactions payments ON ap.transaction_id = payments.id
group by c.company

仅在“from”子句中为表提供别名不会使其在查询中其他位置的子查询中可用。

我还添加了一个GROUP BY子句,因为您的查询似乎是由公司聚合的。