5

私は基本的に、すべての日付のカウントを保持するテーブルを持っています。昨日の合計だけでなく、テーブル全体のカウントの合計数を取得するクエリを作成したいと考えています。しかし、テーブルに 2 回参加しようとすると、集計がオフになります。以下は、結果を再現する方法です。

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" の 4 つの行と一致します。それはすべて大丈夫です。しかし、結合を 3 番目のテーブル (「y」) に追加すると、その 3 番目の「y」テーブル (2 つの行) から返された各行は、「b」テーブルのすべての行と「一致」します。結果セットには合計 8 行が含まれます。(そのため、「total_count」が 2 倍になっています。)

指定した結果セットを取得するために、そのテーブル "b" に 2 回参加する必要はありません。代わりに、条件付きテストを使用して、その「カウント」を合計「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;

移植性を向上させるために、MySQLIF式を同等の ANSI 式に置き換えることができることに注意してください。CASE

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

その「b」テーブルにもう一度 JOIN を実行したい場合は、JOIN 条件を、「y」からの行が「b」からの最大でも 1 行に一致するようにする必要があります。重複を導入します。したがって、主キーにすべての列を含めるには、基本的に結合条件が必要です。

(テーブル "y" の結合条件の述語は、"y" からのそれぞれが "b" からの 1 つの行のみと一致することを保証することに注意してください):

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 に答える