SUM函数两次添加记录

时间:2019-07-02 08:41:11

标签: mysql sql

我的数据库中有2条记录金额,我必须使用sum函数来显示总额,但它显示并求和两次

我在同一查询中尝试了另一个求和函数,但在我第二次使用它时,它求和两次。

$sql = "SELECT 
                mm.idno as idno,
                TRIM(UPPER(CONCAT(mm.fname, ' ', mm.mname, ' ', mm.lname))) as fullname, 
                TRIM(UPPER(mm.branchname)) as branchname, 
                TRIM(UPPER(mm.address)) as outlet_address, 
                SUM(dr.totalamt) as total_amount,
                SUM(drr.totalamt) as return_amount  
        FROM 8_membermain mm
            LEFT JOIN 8_directsalessummary dr ON mm.idno = dr.idno
            LEFT JOIN 8_drreturnsummary drr ON dr.idno = drr.idno
        WHERE mm.status > 0 AND dr.status = 1
        AND dr.ispaid = 'Full Payment'
        AND dr.trandate BETWEEN '".$date1."' AND '".$date2."' 
        AND drr.trandate BETWEEN '".$date1."' AND '".$date2."'";

SUM(dr.totalamt) as total_amount工作正常。唯一的问题是SUM(drr.totalamt) as return_amount

2 个答案:

答案 0 :(得分:2)

您的方法存在的问题是您先先加入两次,然后再进行汇总。 SUM(dr.totalamt)之所以有效,是因为它只涉及第一个联接。但是SUM(drr.totalamt)是不正确的,因为由于第二个联接,您正在计数过多。要解决此问题,您应该在单独的子查询中执行聚合,然后加入这些子查询:

SELECT
    mm.idno,
    TRIM(UPPER(CONCAT(mm.fname, ' ', mm.mname, ' ', mm.lname))) AS fullname,
    TRIM(UPPER(mm.branchname)) AS branchname,
    TRIM(UPPER(mm.address)) AS outlet_address, 
    COALESCE(dr.totalamt, 0) AS total_amount,
    COALESCE(drr.totalamt, 0) AS return_amount
FROM 8_membermain mm
LEFT JOIN
(
    SELECT idno, SUM(totalamt) AS totalamt
    FROM 8_directsalessummary
    WHERE status = 1 AND ispaid = 'Full Payment' AND
        trandate BETWEEN ? AND ?
    GROUP BY idno
) dr
    ON mm.idno = dr.idno
LEFT JOIN
(
    SELECT idno, SUM(totalamt) AS totalamt
    FROM 8_drreturnsummary
    WHERE trandate BETWEEN ? and ?
    GROUP BY idno
) drr
    ON mm.idno = drr.idno
WHERE
    mm.status > 0;

对于?占位符,您需要绑定两个日期值$date1$date2。但是,关于如何在PHP中使用准备好的语句的其他解释似乎过于广泛,而且查询逻辑问题似乎是更大的问题。

答案 1 :(得分:2)

从对问题的描述中,听起来您的查询匹配两个dr行和一个drr行。如果有不止一个drr列,则dr总数也将是错误的。这是因为联接返回联接表的所有可能组合。例如,如果有两个dr行,我们将分别称为A和B,以及三个drr行C,D和E,则结果(由于使用sum而没有分组依据,因此将它们分组为一行) )应该是:

A and C
A and D
A and E
B and C
B and D
B and E

在对dr列求和时,A和B的值分别遇到3次,导致总和增加了三倍。在对drr列求和时,C,D和E的值分别遇到两次,导致总和加倍。

正确的解决方法是加入dr和drr的子查询,如Tim的答案所示。但是有时候,如果涉及的表很少,并且每个分组中的大多数记录很少,并且这些表具有主键或其他唯一列,则可以简单地将每个总和除以其他表中的行数(或1(如果没有行):

SELECT
    ...
    SUM(dr.totalamt)/GREATEST(1,COUNT(DISTINCT drr.primarykey)) as total_amount,
    SUM(drr.totalamt)/GREATEST(1,COUNT(DISTINCT dr.primarykey)) as return_amount

关于您的查询的其他一些评论:

似乎您打算在末尾添加一个GROUP BY mm.idno;否则,您的查询将返回与您的where条件相匹配的任意mm记录的mm相关字段的数据,并且如果您的查询实际上找到了多个mm记录,则上述技巧将无法正常工作。

您使用左联接,但是在where子句中指定条件,如果找不到行,则条件为false;这实际上使您的左联接成为内部联接。如果要查找毫米行,甚至没有dr或drr行,则需要将条件移到联接中,例如:

LEFT JOIN 8_directsalessummary dr ON mm.idno = dr.idno
    AND dr.status = 1
    AND dr.ispaid = 'Full Payment'
    AND dr.trandate BETWEEN ...

此外,您正在使用dr.idno加入drr;如果即使没有dr记录也要查找drr记录,则应改用mm.idno:

LEFT JOIN 8_drreturnsummary drr ON mm.idno = drr.idno
    AND drr.trandate BETWEEN ...