2013-02-28 33 views
0

我正在尝试进行报告。它应该给我一个特定客户的机器清单以及放入该机器的小时数和材料总和。具有多个左连接的错误值(MySQL)

在下面的例子中,我选择不同领域的材料和小时数的总和,以使问题更清楚。但我真的想把这些材料总结一小时,然后在机器领域分组。

我可以查询机器列表和小时数没有问题的成本。

SELECT CONCAT(`customer`.`PREFIX`, `wo`.`machine_id`) AS `machine`, 
     ROUND(COALESCE(SUM(`wohours`.`length` * `wohours`.`price`), 0), 2) AS `hours` 

FROM `wo` 
JOIN `customer` ON `customer`.`id`=`wo`.`customer_id` 
LEFT JOIN `wohours` ON `wohours`.`wo_id`=`wo`.`id` AND `wohours`.`wo_customer_id`=`wo`.`customer_id` 
        AND `wohours`.`wo_machine_id`=`wo`.`machine_id` AND `wohours`.`date`>=(CURDATE() - INTERVAL DAY(CURDATE() - INTERVAL 1 DAY) DAY) - INTERVAL 11 MONTH 

WHERE `wo`.`customer_id`=1 
GROUP BY `wo`.`machine_id`; 

这给了我几个小时的正确值。但是当我添加这样的材料时:

SELECT CONCAT(`customer`.`PREFIX`, `wo`.`machine_id`) AS `machine`, 
     ROUND(COALESCE(SUM(`wohours`.`length` * `wohours`.`price`), 0), 2) AS `hours`, 
     ROUND(COALESCE(SUM(`womaterial`.`multiplier` * `womaterial`.`price`), 0), 2) AS `material` 

FROM `wo` 
JOIN `customer` ON `customer`.`id`=`wo`.`customer_id` 
LEFT JOIN `wohours` ON `wohours`.`wo_id`=`wo`.`id` AND `wohours`.`wo_customer_id`=`wo`.`customer_id` 
      AND `wohours`.`wo_machine_id`=`wo`.`machine_id` AND `wohours`.`date`>=(CURDATE() - INTERVAL DAY(CURDATE() - INTERVAL 1 DAY) DAY) - INTERVAL 11 MONTH 
LEFT JOIN `womaterial` ON `womaterial`.`wo_id`=`wo`.`id` AND `womaterial`.`wo_customer_id`=`wo`.`customer_id` 
      AND `womaterial`.`wo_machine_id`=`wo`.`machine_id` AND `wohours`.`date`>=(CURDATE() - INTERVAL DAY(CURDATE() - INTERVAL 1 DAY) DAY) - INTERVAL 11 MONTH 

WHERE `wo`.`customer_id`=1 
GROUP BY `wo`.`machine_id`; 

然后小时和材料值都不正确。

我读过其他线程,其中有相似问题的人可以通过将其拆分为多个查询或子查询来解决此问题。但我认为在这种情况下这是不可能的。

任何帮助表示赞赏。

//约翰

回答

1

您的其他阅读是正确的。您需要将它们放入它们自己的“子查询”中进行连接。您可能获得无效值的原因是材料表每台计算机有多个记录,因此会导致基于小时的原始笛卡尔结果。而且你不知道哪一个有很多,而只有一个让它看起来不正确。

所以,我写了,每个预先聚合woHours和woMaterial的最内层查询将产生一个记录,每个“wo_id和machine_id”在完成时返回到wo表。这些查询中的每一个都有您试图运行它的单个客户ID的标准。

然后,当重新加入工作单(wo)表时,它抓取所有记录并应用ROUND()和COALESCE(),以防没有这样的小时或材料出现。因此,这是一个类似

WO Machine ID Machine Hours Material 
1  1    CustX 1 2  0 
2  4    CustY 4 2.5  6.5 
3  4    CustY 4 1.2  .5 
4  1    CustX 1 1.5  1.2 

最后一回,你现在可以卷起所有这些条目的SUM()到每个机器ID

Machine Hours Material 
CustX 1 3.5  1.2 
CustY 4 3.7  7.0 


SELECT 
     AllWO.Machine, 
     SUM(AllWO.Hours) Hours, 
     SUM(AllWO.Material) Material 
    from 
     (SELECT 
       wo.wo_id, 
       wo.Machine_ID, 
       CONCAT(customer.PREFIX, wo.machine_id) AS machine, 
       ROUND(COALESCE(PreSumHours.MachineHours, 0), 2) AS hours, 
       ROUND(COALESCE(PreSumMaterial.materialHours, 0), 2) AS material 
      FROM 
       wo 
       JOIN customer 
        ON wo.customer_id = customer.id 

       LEFT JOIN (select wohours.wo_id, 
            wohours.wo_machine_id, 
            SUM(wohours.length * wohours.price) as machinehours 
           from 
            wohours 
           where 
             wohours.wo_customer_id = 1 
            AND wohours.date >= (CURDATE() - INTERVAL DAY(CURDATE() - INTERVAL 1 DAY) DAY) - INTERVAL 11 MONTH 
           group by 
            wohours.wo_id, 
            wohours.wo_machine_id) as PreSumHours 
        ON wo.id = PreSumHours.wo_id 
        AND wo.machine_id = PreSumHours.wo_machine_id 

       LEFT JOIN (select womaterial.wo_id, 
            womaterial.wo_machine_id, 
            SUM(womaterial.length * womaterial.price) as materialHours 
           from 
            womaterial 
           where 
             womaterial.wo_customer_id = 1 
            AND womaterial.date >= (CURDATE() - INTERVAL DAY(CURDATE() - INTERVAL 1 DAY) DAY) - INTERVAL 11 MONTH 
           group by 
            womaterial.wo_id, 
            womaterial.wo_machine_id) as PreSumMaterial 
        ON wo.id = PreSumMaterial.wo_id 
        AND wo.machine_id = PreSumMaterial.wo_machine_id 
      WHERE 
       wo.customer_id = 1) AllWO 
    group by 
     AllWO.Machine_ID 
+0

这是真棒单行。奇迹般有效。 – John 2013-02-28 19:38:09

+0

我不知道你可以加入子查询。有很多东西需要学习。无论如何...再次感谢。 – John 2013-02-28 19:39:20

+0

你如何构建这样的查询?你只是从上到下写下它们,还是你有一个方法呢? – John 2013-02-28 19:45:11