Add up conditional counts on multiple columns of the same table

后端 未结 4 1252
清歌不尽
清歌不尽 2021-01-21 01:16

I am looking for a \"better\" way to perform a query in which I want to show a single player who he has played previously and the associated win-loss record for each such oppone

4条回答
  •  自闭症患者
    2021-01-21 02:03

    Something more readable than my original. Thoughts?

    with W as (
        select loser_id as opponent_id,
        count(*) as n
        from match
        where winner_id = 1
        group by loser_id
    ),
    L as (
        select winner_id as opponent_id,
        count(*) as n
        from match
        where loser_id = 1
        group by winner_id
    )
    select player.username, coalesce(W.n, 0) as wins, coalesce(L.n, 0) as losses
    from player
    left join W on W.opponent_id = player.player_id
    left join L on L.opponent_id = player.player_id
    where player.player_id != 1;
    
                                     QUERY PLAN                                  
    -----------------------------------------------------------------------------
     Hash Left Join  (cost=73.78..108.58 rows=1224 width=48)
       Hash Cond: (player.player_id = l.opponent_id)
       CTE w
         ->  HashAggregate  (cost=36.81..36.83 rows=2 width=4)
               Group Key: match.loser_id
               ->  Seq Scan on match  (cost=0.00..36.75 rows=11 width=4)
                     Filter: (winner_id = 1)
       CTE l
         ->  HashAggregate  (cost=36.81..36.83 rows=2 width=4)
               Group Key: match_1.winner_id
               ->  Seq Scan on match match_1  (cost=0.00..36.75 rows=11 width=4)
                     Filter: (loser_id = 1)
       ->  Hash Left Join  (cost=0.07..30.15 rows=1224 width=44)
             Hash Cond: (player.player_id = w.opponent_id)
             ->  Seq Scan on player  (cost=0.00..25.38 rows=1224 width=36)
                   Filter: (player_id <> 1)
             ->  Hash  (cost=0.04..0.04 rows=2 width=12)
                   ->  CTE Scan on w  (cost=0.00..0.04 rows=2 width=12)
       ->  Hash  (cost=0.04..0.04 rows=2 width=12)
             ->  CTE Scan on l  (cost=0.00..0.04 rows=2 width=12)
    

    The above has a performance killer with the player_id != 1. I think I can avoid that by only scanning the results of the joins, no?

    explain with W as (
            select loser_id as opponent_id,
            count(*) as n
            from match
            where winner_id = 1 
            group by loser_id
        ),  
        L as (
            select winner_id as opponent_id,
            count(*) as n
            from match
            where loser_id = 1 
            group by winner_id
        )   
        select t.* from (
            select player.player_id, player.username, coalesce(W.n, 0) as wins, coalesce(L.n, 0) as losses
            from player
            left join W on W.opponent_id = player.player_id
            left join L on L.opponent_id = player.player_id
        ) t 
        where t.player_id != 1;
    
                                     QUERY PLAN                                  
    -----------------------------------------------------------------------------
     Hash Left Join  (cost=73.78..74.89 rows=3 width=52)
       Hash Cond: (player.player_id = l.opponent_id)
       CTE w
         ->  HashAggregate  (cost=36.81..36.83 rows=2 width=4)
               Group Key: match.loser_id
               ->  Seq Scan on match  (cost=0.00..36.75 rows=11 width=4)
                     Filter: (winner_id = 1)
       CTE l
         ->  HashAggregate  (cost=36.81..36.83 rows=2 width=4)
               Group Key: match_1.winner_id
               ->  Seq Scan on match match_1  (cost=0.00..36.75 rows=11 width=4)
                     Filter: (loser_id = 1)
       ->  Hash Left Join  (cost=0.07..1.15 rows=3 width=44)
             Hash Cond: (player.player_id = w.opponent_id)
             ->  Seq Scan on player  (cost=0.00..1.05 rows=3 width=36)
                   Filter: (player_id <> 1)
             ->  Hash  (cost=0.04..0.04 rows=2 width=12)
                   ->  CTE Scan on w  (cost=0.00..0.04 rows=2 width=12)
       ->  Hash  (cost=0.04..0.04 rows=2 width=12)
             ->  CTE Scan on l  (cost=0.00..0.04 rows=2 width=12)
    

提交回复
热议问题