【问题标题】:How do I get a SUM to calculate properly with a join?如何通过连接正确计算 SUM?
【发布时间】:2011-11-06 05:04:15
【问题描述】:

所以我试图计算零件的数量、任务的数量、每项工作的数量以及制造每项工作所花费的时间,但我得到了一些奇怪的结果。如果我运行这个:

SELECT
  j.id, 
    mf.special_instructions,
  count(distinct p.id) as number_of_different_parts,
  count(distinct t.id) as number_of_tasks,
  SUM(distinct j.quantity) as number_of_assemblies,
  SUM(l.time_elapsed) as time_elapsed

FROM
  sugarcrm2.mf_job mf
INNER JOIN ramses.jobs j on
  mf.id = j.mf_job_id
INNER JOIN ramses.parts p on
  j.id = p.job_id
INNER JOIN ramses.tasks t on
  p.id = t.part_id
INNER JOIN ramses.batch_log l on
  t.batch_id = l.batch_id

WHERE 
  mf.job_description                LIKE "%BACKBLAZE%" OR
  mf.customer_name                  LIKE "%BACKBLAZE%" OR
  mf.customer_ref                   LIKE "%BACKBLAZE%" OR
  mf.technical_company_name LIKE "%BACKBLAZE%" OR
  mf.description                        LIKE "%BACKBLAZE%" OR
  mf.name                                   LIKE "%BACKBLAZE%" OR
  mf.enclosure_style                LIKE "%BACKBLAZE%" OR 
    mf.special_instructions     LIKE "%BACKBLAZE%"
Group by j.id

我现在得到了准确的零件和任务编号,但 time_elapsed 总和不正确。问题可能是什么?

当我用distinct 尝试它时,我得到一个非常低的数字(当我在寻找接近 10,000 的东西时,就像 1 到 30 之间的数字。)

更新:这里是创建代码:

http://pastebin.com/nbhU9rYh

http://pastebin.com/tdmAkNr4

http://pastebin.com/0TFCUaeQ

http://pastebin.com/fugr8C9U

http://pastebin.com/Zq0bKG2L

http://pastebin.com/k5rESUrq

关系是这样的:

  • mf_job 信息已链接到作业
  • 工作有部分
  • 零件有任务
  • 任务分批进行
  • batch_log 是一个包含批次任务的所有开始和停止的表,它有一个 start_time 和一个 stop_time 以及一个 time_elapsed。

我正在尝试从每个 mf_job 的 batch_log 中获取所有 time_elapsed,其中一个字段中带有单词 backblaze,以及零件、任务和组件的数量。这一切都需要按 job.id 或 mf_job.id 分组

【问题讨论】:

  • @Icarus,非常接近,select SEC_TO_TIME(SUM(TIME_TO_SEC(elapsed_time))) 实际上是正确的,函数SECOND() 最多只能给出 59 秒的结果。
  • 请包含表架构。并阐明 elapsed_time 是基于 batch_id 或 batch_id + job_id 的 SUM
  • @dah 你能给出来自 show create table 的列 ddl 吗?
  • 这里相关的是了解表之间关系的行为。基本上,什么连接会导致重复。然后,您可能需要具有嵌套子查询的不同级别的聚合。您对表格及其关系的描述越多越好。
  • +1 将您的几乎所有代表都用于赏金。

标签: mysql sql group-by sum aggregate


【解决方案1】:

您需要将查询更改为:

SELECT
  ...
  SEC_TO_TIME(SUM(TIME_TO_SEC(l.time_elapsed))) as time_elapsed

另外,LIKE '%...' 的行会使查询变得非常慢,因为这上面没有索引可以使用。

如果您能够使用 MyISAM,您可以在这些列上使用全文索引并使用如下代码:

WHERE MATCH(mf.job_description,mf.customer_name,mf.customer_name,...) 
      AGAINST ('BACKBLAZE' IN NATURAL LANGUAGE MODE)

见:
http://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html
http://www.petefreitag.com/item/477.cfm
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_time-to-sec

【讨论】:

  • 我们实际上正在使用 innodb,我尝试更改查询,但现在我仍然得到错误的秒数。
【解决方案2】:

听起来问题是多个任务可以在同一个批次中,和/或多个部分可以在同一个任务中。比如说你的工作有 3 个部分,每个部分都有一个任务,所有 3 个任务都在同一个批次中。您将为该批次添加 3 次时间。但是 distinct 也不起作用,因为如果您有 5 个不同的批次都花费了 300 秒,它们将不会被认为是不同的。

在这种情况下,子查询通常是要走的路。不是直接加入batch_log,而是加入一个选择不同j.id(或p.job_id)、l.batch_idl.time_elapsed 的子查询(第一个用于加入,第二个用于正确计算distinct,第三个是要使用的实际值)。然后你可以从那里总结l.time_elapsed。这样每个批次都只计算一次。

【讨论】:

    【解决方案3】:

    尝试将查询重写为:

    SELECT
      j.id, 
      mf.special_instructions,
      count(p.id) as number_of_different_parts,
      count(t.id) as number_of_tasks,
      SUM(j.quantity) as number_of_assemblies,
      SEC_TO_TIME(SUM(l.seconds_elapsed)) as time_elapsed
    
    FROM
      sugarcrm2.mf_job mf
    INNER JOIN ramses.jobs j on
      mf.id = j.mf_job_id
    INNER JOIN ramses.parts p on
      j.id = p.job_id
    INNER JOIN ramses.tasks t on
      p.id = t.part_id
    INNER JOIN (
                SELECT rl.batch_id
                      , SUM(TIME_TO_SEC(rl.time_elapsed)) as seconds_elapsed
                FROM ramses.batch_log rl 
                GROUP BY rl.batch_id
                ) l ON (t.batch_id = l.batch_id)
    
    WHERE 
      mf.job_description                LIKE "%BACKBLAZE%" OR
      mf.customer_name                  LIKE "%BACKBLAZE%" OR
      mf.customer_ref                   LIKE "%BACKBLAZE%" OR
      mf.technical_company_name         LIKE "%BACKBLAZE%" OR
      mf.description                    LIKE "%BACKBLAZE%" OR
      mf.name                           LIKE "%BACKBLAZE%" OR
      mf.enclosure_style                LIKE "%BACKBLAZE%" OR 
      mf.special_instructions           LIKE "%BACKBLAZE%"
    GROUP BY j.id WITH ROLLUP
    

    【讨论】:

      【解决方案4】:

      batches(l) 表没有名为 time_elapsed 的字段 任务是这样做的,要么是

      SUM(t.time_elapsed) as time_elapsed
      

      -或-

      SUM(l.actual_time) as time_elapsed
      

      【讨论】:

        猜你喜欢
        • 2021-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-02
        • 2016-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多