【问题标题】:Mysql : JOIN 2 table , one of the SUM is not correctMysql:JOIN 2 表,其中一个 SUM 不正确
【发布时间】:2015-12-08 11:45:22
【问题描述】:

这是两张表的结构

表 A

+----+-----+----+----------------------+--------------------+----------+
| id | ... |....|   time_start         | time_end           |  total   | 
+----+-----+----+----------------------+--------------------+----------+
  1               2015-12-06 10:00:00    2015-12-06 12:00:00     200
  2               2015-12-07 10:00:00    2015-12-07 12:00:00     300              

表 B

+----+----------+------+------+------+------+
| id | idTableA | val1 | val2 | val3 | val4 |   
+----+----------+------+------+------+------+
  1        1       10     10     10     10
  2        1       10     10     10     10
  3        2       10     10     10     10

目标如下:给定一个 time_start 和一个 time_end 日期,显示总和(表 A)和 val1、val2 的总和, val3,val4

示例

  • time_start = 2015-12-01 00:00:00

  • time_end = 2015-12-30 23:59:59

预期结果:总和 = 500,val(1-4) 总和 = 120

我试过了:

$myquery = "";
$myquery .= "SELECT SUM(tableA.total) AS myTotal,";
$myquery .= "SUM(tableB.val1) + SUM(tableB.val2) + SUM(tableB.val3) + SUM(tableB.val4) AS myValTotal ";
$myquery .= "FROM tableA INNER JOIN tableB ON tableA.id = tableB.idTableA ";
$myquery .= "WHERE tableA.time_start >='".$dateStart."' AND tableA.time_end <='".$dateEnd."'";

val(1-4) 的 SUM 是正确的,但 total 的 SUM 不是。

【问题讨论】:

  • 只加括号: $myquery .= "SUM(SUM(tableB.val1) + SUM(tableB.val2) + SUM(tableB.val3) + SUM(tableB.val4)) AS myValTotal " ;
  • 请说明总和是怎么来的,只有这样才能做到,值的总和也是如此
  • @KrishnaGupta 我试过了,但没有任何改变
  • @mugdha tableA.total 和 tableB.val1,tableB.val2,tableB.val3,tableB.val4 是不同类型的值。 tableA.total 不是 va1,val2,val3,val4 的总和
  • 你使用了我更新的评论??

标签: php mysql sql join


【解决方案1】:

在加入之前汇总您的数据,这样您就不会错误地考虑多重价值。

select sum(a.total) as mytotal, sum(b.sumval) as myvaltotal
from tablea a
left join
(
  select idtablea, sum(val1+val2+val3+val4) as sumval
  from tableb
  group by idtablea
) b on b.idtablea = a.id
where a.time_start >= @start and a.time_end <= @end;

这与 SELECT 子句中的子查询相同。它更简单,并且绕过了 Juan Carlos Oropeza 在下面的 cmets 中描述的问题。

select 
  sum(total) as mytotal, 
  sum((
    select sum(val1+val2+val3+val4)
    from tableb
    where idtablea = tablea.id
  )) as sumvaltotal
from tablea
where time_start >= @start and time_end <= @end;

【讨论】:

  • 即使这项工作非常简单,如果表很大,您必须小心性能,因为第二个子查询没有任何过滤器,并且连接不会使用任何索引。
  • @Juan Carlos Oropeza:我认为没有理由不这样做。但是,您是对的,查询的编写方式是仅在聚合所有 tableB 记录后才应用过滤器。如果 tableB 有许多超出给定范围的记录,这可能会导致很多不必要的工作。但通常好的 DBMS 会在内部处理此问题并尽快应用过滤器(连接标准),以免产生不必要的开销。可以通过添加where idtablea in (select id from tablea where time_start ...) 来确保,但如前所述,一个好的 DBMS 无论如何都会在内部做到这一点。
  • @Juan Carlos Oropeza:谢谢你的发言。我为我的答案添加了一个替代方案,它完全绕过了一个大的中间结果。
  • @ThorstenKettner 我尝试了第二种解决方案,我在 phpmyadmin 上尝试过,但说:“存在语法错误......”。 "SELECT SUM(total) AS mytotal,(SUM(val1+val2+val3+val4) AS sumval FROM tableb WHERE idtablea = tablea.id) AS sumvaltotal FROM tablea WHERE time_start >= '".$dayStart."' and time_end
  • 很抱歉。我在两个查询中都有错误(总和(总)而不是总和)。加上第二个查询中缺少的select。我希望它现在可以工作。
【解决方案2】:

您不应该对行的乘法进行聚合。而是独立聚合两个表,然后将它们连接起来,例如:

select * from
(
SELECT SUM(tableA.total) AS myTotal
FROM tableA 
WHERE tableA.time_start <= @dateEnd 
  AND tableA.time_end >=  @dateStart
) x join (
SELECT SUM(tableB.val1) + SUM(tableB.val2) + 
       SUM(tableB.val3) + SUM(tableB.val4) AS myValTotal 
FROM tableB join  tableA ON tableA.id = tableB.idTableA
WHERE tableA.time_start <= @dateEnd 
  AND tableA.time_end >=  @dateStart
) y;

【讨论】:

    【解决方案3】:

    你必须检查你想要什么样的数据范围重叠,如果部分或全部。

    Determine Whether Two Date Ranges Overlap

    另外,最好的测试方法是先将查询直接复制到数据库中。

    检查WHERE中的数据范围

    SET @dateStart= '2015-12-01 00:00:00';
    SET @dateEnd = '2015-12-30 23:59:59';
    
    SELECT myTotal, myValTotal 
    FROM 
        (
          SELECT SUM(tableA.total) AS myTotal
          FROM tableA
          WHERE tableA.time_start >= @dateStart
            AND tableA.time_end <=  @dateEnd ;
        ) T1
    CROSS JOIN 
        (
            SELECT SUM(tableB.val1 + tableB.val2 + tableB.val3 + tableB.val4) AS myValTotal 
            FROM tableA 
            INNER JOIN tableB 
                    ON tableA.id = tableB.idTableA
            WHERE tableA.time_start >= @dateStart
              AND tableA.time_end <=  @dateEnd
       ) T2;
    

    【讨论】:

    • 不是日期问题。请查看@HoneyBadger 评论,谢谢
    • 好的,我更新我的答案。我使用您的 WHERE 范围,但我仍然相信您应该检查我的链接以确定范围重叠
    【解决方案4】:

    作为一个起点,这似乎更容易阅读......

    $myquery = 
     "
     SELECT SUM(a.total) myTotal
          , SUM(b.val1 + b.val2 + b.val3 + b.val4) myValTotal
       FROM tableA a
       JOIN tableB b
         ON b.idTableA = a.id 
      WHERE a.time_start >='$dateStart' 
        AND a.time_end   <='$dateEnd'
     ";
    

    【讨论】:

      【解决方案5】:

      您可以声明 int 类型的变量并存储总和值,然后再次对存储的值求和以获得总值

                declare  @val1 int
                declare @val2 int
                declare @val3 int
                declare @val4 int
                declare @newval int
      
                  select @val1= SUM(isnull(val1,0)) , @val2 =
                  sum(isnull(val2,0)), @val3=sum(isnull(val3,0)),@val4 = 
                  sum(isnull(val2,0)) from TableB
      
                  select @newval = @val1 +@val2+@val3+@val4
      

      @newval 将包括 val1 到 val4 的总和

      【讨论】:

        【解决方案6】:
        SELECT  
        SUM(tableB.val1) + SUM(tableB.val2) + SUM(tableB.val3) + SUM(tableB.val4) AS myValTotal,
        (SELECT SUM(total) from tableA  where   tableA.time_start >='2015-12-01 00:00:00' AND tableA.time_end <= '2015-12-30 23:59:59') as myTotal 
        FROM tableA  INNER JOIN tableB ON tableA.id = tableB.idTableA 
        WHERE tableA.time_start >='2015-12-01 00:00:00' AND tableA.time_end <= '2015-12-30 23:59:59'
        

        【讨论】:

          猜你喜欢
          • 2011-08-06
          • 1970-01-01
          • 2012-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-04
          • 1970-01-01
          相关资源
          最近更新 更多