sql >> データベース >  >> RDS >> Mysql

MySQL:JOINを指定したSUM()が誤った値を返す

    このクエリを試してください:

    SELECT bl.user_id, SUM( ph.amount ) PAIDOUT
    FROM (
       SELECT distinct blocks.user_id 
       FROM blocks
       WHERE confirms > 520
    ) bl
    LEFT JOIN  payout_history ph
    ON bl.user_id = ph.user_id
    GROUP BY ph.user_id
    ;
    

    SQLFiddle-> http://sqlfiddle.com/#!2/7b988/48



    ---編集---クエリがどのように機能するか(またはクエリが機能しない理由)の説明----

    期待される結果を見ると、クエリはamountの合計を計算する必要があるようです。 各user_idの列 、ただし、これらのuser_idのみ 、これもblocksにあります テーブル、およびblocks.confirmsがあります 520ではなく値が大きくなります。
    この場合、blocksのため、単純な結合(左外部結合も)は機能しません。 テーブルには、同じuser_idの多くのレコードを含めることができます たとえば、user_id=110のみの行を返すクエリ 次の結果が得られます:

    SELECT *
    FROM blocks
    WHERE confirms > 520
          AND user_id = 110;
    
    + ------- + ------------ + ----------- + ------------- +
    | id      | user_id      | reward      | confirms      |
    + ------- + ------------ + ----------- + ------------- +
    | 0       | 110          | 20.89832115 | 521           |
    | 65174   | 110          | 3.80357075  | 698           |
    | 65204   | 110          | 4.41933060  | 668           |
    | 65218   | 110          | 4.69059801  | 654           |
    | 65219   | 110          | 4.70222521  | 653           |
    | 65230   | 110          | 4.82805490  | 642           |
    | 65265   | 110          | 5.25058079  | 607           |
    | 65316   | 110          | 6.17262650  | 556           |
    + ------- + ------------ + ----------- + ------------- +
    

    ストレート結合(およびLEFT / RIGHT外部結合)はこのように機能し、最初の結合テーブルから各レコードを取得し、このレコードを他の結合テーブルのすべての行とペアにして(結合)、結合条件を満たす。

    この場合、左結合は以下の結果セットを生成します:

    SELECT *
    FROM blocks
    LEFT JOIN payout_history
    ON blocks.user_id = payout_history.user_id
    WHERE confirms > 520
        AND blocks.user_id = 110;
    + ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
    | id      | user_id | reward      | confirms | id  | user_id | amount      |
    + ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
    | 0       | 110     | 20.89832115 | 521      | 1   | 110     | 20.898319   |
    | 65174   | 110     | 3.80357075  | 698      | 1   | 110     | 20.898319   |
    | 65204   | 110     | 4.41933060  | 668      | 1   | 110     | 20.898319   |
    | 65218   | 110     | 4.69059801  | 654      | 1   | 110     | 20.898319   |
    | 65219   | 110     | 4.70222521  | 653      | 1   | 110     | 20.898319   |
    | 65230   | 110     | 4.82805490  | 642      | 1   | 110     | 20.898319   |
    | 65265   | 110     | 5.25058079  | 607      | 1   | 110     | 20.898319   |
    | 65316   | 110     | 6.17262650  | 556      | 1   | 110     | 20.898319   |
    + ------- + ------- + ----------- + -------- + --- + ------- + ----------- +
    

    ここで、SUM( amount ) .... GROUP BY user_idを追加すると 、MySqlはすべてのamountの合計を計算します 上記の結果セットの値(8行* 20.898 =〜167.184)

    SELECT blocks.user_id, sum( amount)
    FROM blocks
    LEFT JOIN payout_history
    ON blocks.user_id = payout_history.user_id
    WHERE confirms > 520
        AND blocks.user_id = 110
    GROUP BY blocks.user_id;
    + ------------ + ----------------- +
    | user_id      | sum( amount)      |
    + ------------ + ----------------- +
    | 110          | 167.186554        |
    + ------------ + ----------------- +
    



    この場合、結合によって望ましい結果が得られません。a semi joinという名前のコードが必要です。 -以下は半結合のさまざまなバリエーションです。試してみてください:

    SELECT bl.user_id, SUM( ph.amount ) PAIDOUT
    FROM (
       SELECT distinct blocks.user_id 
       FROM blocks
       WHERE confirms > 520
    ) bl
    LEFT JOIN  payout_history ph
    ON bl.user_id = ph.user_id
    GROUP BY ph.user_id
    ;
    
    
    SELECT ph.user_id, SUM( ph.amount ) PAIDOUT
    FROM payout_history ph
    WHERE ph.user_id IN (
         SELECT user_id FROM blocks
         WHERE confirms > 520
      )
    GROUP BY ph.user_id
    ;
    
    SELECT ph.user_id, SUM( ph.amount ) PAIDOUT
    FROM payout_history ph
    WHERE EXISTS (
         SELECT 1 FROM blocks bl
         WHERE bl.user_id = ph.user_id
            AND bl.confirms > 520
      )
    GROUP BY ph.user_id
    ;
    


    1. 除算(/)がpostgresqlで私の答えを与えていない

    2. MySQLにインデックスによるFIND_IN_SETはありますか?

    3. MySQLパフォーマンスの最適化:日時フィールドによる順序

    4. MySQLクエリから繰り返される結果を削除する