在多行上使用LEFT JOIN简化我的SQL

时间:2015-06-15 10:22:16

标签: mysql sql performance left-join

我现在对MySQL和高效查询有相当的经验,但仍遇到问题......

我有两张表,“发票”和“salesRecords”发票表包含发票的基本概览,销售记录逐行分解有关购买物品的特定信息。

为简单起见,我们假设表格如下:

发票

id    |   repairCharge     |    shippingCharge      |     total
 1    |       28.95        |         0              |     30.45   
 2    |       10.00        |         8.50           |     29.50

//注意;总列包括销售记录中显示的项目

SalesRecords

invNo  |    itemNo   |  price    |   quantity   | discount  |   
  1    |     123     |  1.50     |      1       |     0     |  
  2    |     121     |  6.50     |      1       |     1.5   |  
  2    |     128     |  5.50     |      1       |     0     |  

我想在一个日期期间获得所售商品,人工费和运费的总价值,因此我需要:

  1. 汇总发票表中的所有行
  2. JOIN(左?)SalesRecords表ON invNo和SUM((价格折扣)*数量)
  3. 对日期使用WHERE子句
  4. 我马上写下这个SQL:

    SELECT SUM((sr.price-sr.discount)*sr.quantity) as income,   
       SUM(i.repairCharge) as labour,
       SUM(i.shippingCharge) as carriage 
    FROM invoices i 
        LEFT JOIN salesRecords sr ON sr.invNo=i.id
    WHERE i.dateTime BETWEEN 1431647999 AND 1434360348`
    

    错误

    因为,对于包含多个项目行的任何发票,我获得了两个表的多个实例,因此repairChargeshippingCharge值加倍或增加三倍,具体取决于产品线的数量在该发票上购买。

    所以,我搞砸了并提出了一个解决方案...但它非常丑陋并且可能效率低下:

    SELECT SUM(income) as income,
           SUM(labour) as labour,
           SUM(carriage) as carriage 
    FROM (SELECT (SELECT SUM((price-discount)*quantity)
                  FROM salesRecords
                  where invno=i.id
                  GROUP BY invNo) as income, 
                 SUM(i.repairCharge) as labour,
                 SUM(i.shippingCharge) as carriage 
          FROM invoices i 
          WHERE i.dateTime BETWEEN 1434326474 AND 1434361694
          GROUP BY id
         ) totals
    

    任何人都可以建议最简化这种方法并提高效率吗?

2 个答案:

答案 0 :(得分:1)

就大多数其他DBMS的易读性和性能而言,我个人只是在子查询中总结销售记录:

SalesRecords

MySQL在子查询上使用中间物化(据我所知),如果这样做,可能会对上述查询产生负面影响,因为它会首先汇总SELECT SUM(COALESCE(i.Income, 0)) AS Income, SUM(i.repairCharge) AS Labour, SUM(i.shippingCharge) AS Carriage FROM ( SELECT i.ID, i.repairCharge, i.shippingCharge, SUM((sr.price - sr.discount) * sr.quantity) AS Income FROM Invoices AS i LEFT JOIN SalesRecords AS sr ON sr.InvNo = i.ID WHERE i.dateTime BETWEEN 1434326474 AND 1434361694 GROUP BY i.ID, i.repairCharge, i.ShippingCharge ) AS i; 中的所有记录并将结果存储在在发票日期应用过滤器之前的哈希表,所以您的工作版本,但使用JOIN而不是相关子查询可能会表现更好:

Sources

答案 1 :(得分:0)

试试这个:

select sum(labour) as labour,
       sum(carriage) as carriage,
       sum(income) as income
from( select sum(i.repairCharge) as labour,
             sum(i.shippingCharge) as carriage,
             coalesce(sum((sr.price - sr.discount) * sr.quantity), 0) as income
      from Invoices i
      left join SalesRecords sr on i.id = sr.invNo
      group by i.id)t