将SUM与左联接一起使用会得到错误的结果

时间:2019-01-28 17:06:47

标签: sql sql-server aggregate-functions

我有:

CREATE TABLE A (id INT,type int,amount int);
INSERT INTO A (id,type,amount) VALUES (1,0,25);
INSERT INTO A (id,type,amount) VALUES (2,0,25);
INSERT INTO A (id,type,amount) VALUES (3,1,10);


CREATE TABLE B (id INT,A_ID int,txt text);
INSERT INTO B (id,A_id,txt) VALUES (1,1,'abc');
INSERT INTO B (id,A_id,txt) VALUES (2,1,'def');
INSERT INTO B (id,A_id,txt) VALUES (3,2,'xxx');

我运行以下查询:

SELECT min(A.id), SUM(A.amount), COUNT(B.id) FROM A
LEFT JOIN B ON A.id = B.A_id
GROUP BY A.type

我明白了:

min(A.id)   SUM(A.amount)   COUNT(B.id)
1           75              3
3           10              0

但是我反而希望得到:

min(A.id)   SUM(A.amount)   COUNT(B.id)
1           50              3
3           10              0

有人可以帮忙吗?实现此精确结果的最佳方法是什么? 我想要group BY类型,并获得分组的A.amount的总和,并获得对应于其外键的所有B的count()。

这是repro:https://www.db-fiddle.com/f/esu13uGLcgFDpX7aEQRMJR/0请运行sql代码。

编辑以添加更多详细信息:如果我删除分组,我们知道结果正确 1、50、2 2、25、1

但是我希望上面的结果,实现它的最佳方法是什么?我想使SUM为TYPE,然后计算与该分组A相关的所有B

3 个答案:

答案 0 :(得分:1)

该解决方案的简短版本。它首先在内部查询中计算B_ID,因此我需要对外部查询中的计数求和。

SELECT  min(A.id), SUM(A.amount), Sum(Bid) FROM A
LEFT JOIN (select count(id) as Bid, A_id from B group by A_id) as Bcount  
ON A.id = Bcount.A_id
GROUP BY A.type

答案 1 :(得分:0)

执行此操作的一种方法是使用ROW_NUMBER()

WITH CTE AS (SELECT A.id AS Aid,
            A.[type],
            A.amount,
            B.id AS bid,
            txt,
            ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY B.id) AS RN
     FROM A
          LEFT JOIN B ON A.id = B.A_ID)
SELECT MIN(Aid) AS Min_A_ID,
       SUM(CASE RN WHEN 1 THEN amount END) AS Amount,
       COUNT(bid) AS BCount
FROM CTE
GROUP BY [type];

我还建议您摆脱该text数据类型并使用varchar(MAX)

答案 2 :(得分:0)

当您从1-N关系求和时,可能会发生这种情况。

匹配的记录可以将结果相乘。

例如,当A中的1条记录与B中的2条记录联接时,它返回GROUP BY之前A量的2倍。因此,SUM然后将A.amount加倍。

一种解决方法是使用子查询一对一连接。

并且COUNT DISTINCT可用于计算唯一ID。
因此,这只是获得A的总和的一种方法。

SELECT 
 q1.type, 
 q1.min_id, 
 q2.amount, 
 COALESCE(q1.totalB, 0) as totalB
FROM 
(
   SELECT 
    A.type,
    MIN(A.id) AS min_id, 
    COUNT(DISTINCT B.id) AS totalB
    FROM A
    LEFT JOIN B ON B.A_id = A.id
    GROUP BY A.type
 ) AS q1
JOIN
(
  SELECT 
   type,
   SUM(amount) AS amount 
  FROM A 
  GROUP BY type
) AS q2 ON q2.type = q1.type

View on DB Fiddle

已针对MySql对SQL进行了测试。但这是可以在几乎所有RDBMS上运行的ANSI标准SQL,包括MS Sql Server。