5

我基本上有一张桌子,里面有每个日期的计数。我想创建一个查询,为我提供整个表的总计数,以及昨天的总数。但是当我尝试加入表两次时,聚合已关闭。以下是如何复制结果。

CREATE TABLE a (id int primary key);
CREATE TABLE b (a_id int, b_id int, date date, count int, primary key (a_id,b_id,date));
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1, UTC_DATE(), 5);
INSERT INTO b VALUES (1, 2, UTC_DATE(), 10);
INSERT INTO b VALUES (1, 1, UTC_DATE()-1, 7);
INSERT INTO b VALUES (1, 2, UTC_DATE()-1, 12);

SELECT A.id,SUM(B.count) AS total_count,SUM(Y.count) AS y FROM a AS A 
LEFT JOIN b AS B ON (B.a_id=A.id) 
LEFT JOIN b AS Y ON (Y.a_id=A.id AND Y.date=UTC_DATE()-1)
GROUP BY A.id;

Results in:
+----+-------------+------+
| id | total_count | y    |
+----+-------------+------+
|  1 |          68 |   76 |
+----+-------------+------+


The correct result should be:
+----+-------------+------+
| id | total_count | y    |
+----+-------------+------+
|  1 |          34 |   22 |
+----+-------------+------+

这里发生了什么?这是 mysql 中的一个错误,还是我不明白连接是如何工作的。

4

2 回答 2

9

不,这不是 MySQL 中的错误。

您的 JOIN 条件正在生成“重复”行。(删除聚合函数和 GROUP BY,你会看到发生了什么。

表“a”中的那一行匹配表“b”中的四行。这一切都很好。但是,当您将联接添加到第三个表(“y”)时,从第三个“y”表(两行)返回的每一行都与“b”表中的每一行“匹配”......所以你会绕结果集中总共有八行。(这就是“total_count”翻倍的原因。)

要获得您指定的结果集,您不需要第二次加入该表“b”。相反,只需使用条件测试来确定“计数”是否应包含在“y”总数中。

例如

SELECT a.id
     , SUM(b.count) AS total_count
     , SUM(IF(b.date=UTC_DATE()-1 ,b.count,0)) AS y
  FROM a a
  LEFT
  JOIN b b ON (b.a_id=a.id)
 GROUP BY a.id;

请注意,IF可以将 MySQL 表达式替换为等效的 ANSICASE表达式以提高可移植性:

     , SUM(CASE WHEN b.date=UTC_DATE()-1 THEN b.count ELSE 0 END) AS y

如果您确实想再次对那个“b”表执行 JOIN,那么您会希望 JOIN 条件使得“y”中的一行最多匹配“b”中的一行,以免引入任何重复项。所以你基本上需要连接条件来包含主键中的所有列。

(请注意,表“y”的连接条件中的谓词保证“y”​​中的每个谓词将匹配“b”中的不超过一行):

SELECT a.id
     , SUM(b.count) AS total_count
     , SUM(y.count) AS y
  FROM a a
  LEFT
  JOIN b b
    ON b.a_id=a.id
  LEFT
  JOIN b y 
    ON y.a_id = b.a_id
   AND y.b_id = b.b_id
   AND y.date = b.date
   AND y.date = UTC_DATE()-1
 GROUP BY a.id;

(要让第一个语句返回相同的结果集,用潜在的 NULL 代替零,您需要将 IF 表达式中的 '0' 常量替换为 'NULL'。

     , SUM(IF(b.date=UTC_DATE()-1 ,b.count,NULL)) AS y
于 2012-12-12T21:10:17.580 回答
5
SELECT A.id,b_count AS total_count,y_count as y
FROM a AS A 
LEFT JOIN (select a_id,SUM(B.Count) b_count from b 
               group by B.A_id) AS B1 ON (B1.a_id=A.id) 
LEFT JOIN (select a_id,SUM(Count) y_count from b
               where date=UTC_DATE()-1
           group by B.A_id) AS Y ON (Y.a_id=A.id) 

SQLFiddle 演示

于 2012-12-12T21:17:47.937 回答