具有多个左连接的错误值(MySQL)

时间:2013-02-28 18:19:09

标签: 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 个答案:

答案 0 :(得分: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

最后,您现在可以将每个计算机ID的所有这些条目的SUM()汇总到一行

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