简体   繁体   中英

Mysql : JOIN 2 table , one of the SUM is not correct

This is the structure of the two tables

Table 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              

Table 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

The goal is the following : given a time_start and a time_end date , display the SUM of the totals (table A) and the SUM of the val1,val2,val3,val4

Example :

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

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

Result expected : sum of total = 500 , sum of val(1-4) = 120

I have tried so :

$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."'";

The SUM of the val(1-4) is correct , but the SUM of total not.

You have to check what kind of data range overlaps you want, if partial or total.

Determine Whether Two Date Ranges Overlap

Also the best way to test it is copy the query direct on the db first.

Check the data range in the 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;

You shouldn't aggregate on multiplication of rows . Rather aggregate two tables independently and then join them, something like:

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;

As a starting point, this seems easier to read...

$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'
 ";
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'

Aggregate your data before you join, so you don't mistakenly consider values multifold.

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;

Here is the same with a subquery in the SELECT clause. It's simpler and circumvents the issue described by Juan Carlos Oropeza in below comments.

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;

You can declare variable of int type and store the sum values , and again sumup the stored values to get value total

          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 will include the sum of val1 to val4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM