2017-05-12 1 views
2

これはデータです:このグループ+サムクエリはより速く実行できるように書き込むことができますか?

me friend game status count 
1 2  gem  done 10 
2 1  gem  done 5 
1 3  gem  done 4 
3 1  gem  done 6 

は、これが私のクエリです:

WITH 
    -- outgoing for all 
    outgoing_for_all AS 
    (SELECT 
    me, 
    sum(count) AS sum 
    FROM game_totals 
    WHERE status IN ('pending', 'done') 
    GROUP BY me), 

    -- incoming for all 
    incoming_for_all AS 
    (SELECT 
    friend, 
    sum(count) AS sum 
    FROM game_totals 
    WHERE status IN ('pending', 'done') 
    GROUP BY friend) 

SELECT 
    me, 
    outgoing_for_all.sum AS outgoing, 
    incoming_for_all.sum AS incoming, 
    outgoing_for_all.sum - incoming_for_all.sum AS score 
FROM outgoing_for_all 
    FULL OUTER JOIN incoming_for_all ON outgoing_for_all.me = incoming_for_all.friend 

これは結果である:それはより速くを行いますので、

me outgoing incoming score 
1 14   11   3 
2 5   10   -5 
3 6   4   2 

は、上記のクエリを書くことができますか? ただ一つのSELECTで合計を行う可能性があると思います。問題は、どのようにしてGROUP BYが正しくなるか分からないので、countを2行1つにまとめることができるということです。

ありがとうございます。

答えて

1

、私はので、私は一つにcount 2から行を合計することができますどのようにGROUP BY正しく知りません。

あなたが右の推測:あなたは、単一の行(count値)を2回(me年代outgoingfriendのための1つの年代incomingに1つずつ)をカウントすることにしたいので、あなたはあなたのすべてを倍にする必要があります行。また、これらの倍増行は別の列でグループ化する必要があります。私たちはそれぞれの行が二回にカウントされなければならないことを正確に知っているので、あなたはCROSS JOINがあまりにも使用することができ、

SELECT me, 
     SUM(count) FILTER (WHERE mul = 1) outgoing, 
     SUM(count) FILTER (WHERE mul = -1) incoming, 
     SUM(mul * count) score 
FROM (
    SELECT me, 1 mul, count 
    FROM game_totals 
    WHERE status IN ('pending', 'done') 
    UNION ALL 
    SELECT friend, -1, count 
    FROM game_totals 
    WHERE status IN ('pending', 'done') 
) t 
GROUP BY me; 

または::

SELECT CASE mul WHEN 1 THEN me ELSE friend END me, 
     SUM(count) FILTER (WHERE mul = 1) outgoing, 
     SUM(count) FILTER (WHERE mul = -1) incoming, 
     SUM(mul * count) score 
FROM  game_totals, (VALUES (1), (-1)) m(mul) 
WHERE status IN ('pending', 'done') 
GROUP BY CASE mul WHEN 1 THEN me ELSE friend END 

しかし:これらは伝統的なアプローチは、通常UNIONで何かありますちょっと読みやすい彼らは実際にあなたのバリアントよりも遅いです。 (私は恐らく、単純なウィンドウ関数はあなたをここで助けません)私はあなたがすでに最速の解決策を見つけたと思います。ただし、インデックスの使用について考える必要があります(既に使用している場合は、moreまたは他のインデックスを使用することをお勧めします)。 F.ex.このインデックスはあなたに多くを助けることができる:

CREATE INDEX idx_game_totals_me_friend_count 
    ON game_totals(me, friend, count) 
    WHERE status IN ('pending', 'done'); 

http://rextester.com/NGAHW3672

2

はい、window functionsを使用すると、両方の合計を1つのクエリで取得できます。問題がある

SELECT 
me, 
sum(count) AS sum over(partition by me) AS outgoing, 
sum(count) AS sum over(partition by friend) AS incoming 
FROM game_totals 
WHERE status IN ('pending', 'done') 
+0

それは本当に期待どおりの結果が返されませんでしたが、それはおそらく近いです。最初にウィンドウ関数を理解する必要があります。参考にしていただきありがとうございます。 – Granga

関連する問題