我的数据库中有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
答案 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 ...