在多个条件下总结总数

时间:2013-10-22 17:33:05

标签: sql postgresql plpgsql

所以我有两个表,球员和比赛结构如下:

                     Table "public.players"
 Column |  Type   |                      Modifiers                       
--------+---------+------------------------------------------------------
 id     | integer | not null default nextval('players_id_seq'::regclass)
 name   | text    | 
 wins   | integer | default 0
 loses  | integer | default 0
 rating | integer | default 1500

                         Table "public.matches"
    Column     |  Type   |                      Modifiers                       
---------------+---------+------------------------------------------------------
 id            | integer | not null default nextval('matches_id_seq'::regclass)
 player1       | integer | 
 player1rating | integer | 
 player2       | integer | 
 player2rating | integer | 
 winner        | boolean | 

如果获胜者是真的,如果球员1赢得那场比赛,那么如果球员2赢得那场比赛则为假。

使用球员表进行简单的赢/输比较很容易,但是我正在观察两位球员相互面对的比较,他们彼此之间的记录是什么。

所以我很困惑我如何总结给定玩家可能被列为player1或player2的条件: P1赢了:

(player1 = <player1> AND winner = true) OR (player2 = <player1> AND winner = false)

P2胜利:

(player1 = <player2> AND winner = true) OR (player2 = <player2> AND winner = false) 

损失将与其他球员的胜利相反。

返回信息的内容如下:

  id  |   name   | wins | loses | rating | wins_v_opp | loses_v_opp
------+----------+------+-------+--------+------------+------------
 4200 | Sinku    |    5 |    48 |   1191 |          1 |          4
 4201 | Kenshiro |   33 |    29 |   1620 |          4 |          1

我在下面的update2之前想出了什么:

CREATE FUNCTION matchup(text, text) AS $$
DECLARE
    player1_name ALIAS FOR $1;
    player2_name ALIAS FOR $2;
BEGIN
    EXECUTE 'SELECT id FROM player WHERE name LIKE $1'
        INTO player1_id
        USING player1_name;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Player1 % not found', player1_name;
    END IF;
    EXECUTE 'SELECT id FROM player WHERE name LIKE $1'
        INTO player2_id
        USING player2_name;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Player2 % not found', player2_name;
    END IF;
    RETURN QUERY EXECUTE 'WITH cte_winners AS (
            SELECT
                CASE WHEN winner THEN m.player1 ELSE m.player2 END AS player,
                COUNT(*) AS wins_v_opp,
                sum(count(*)) over() - COUNT(*) AS loses_v_opp
            FROM matches AS m
            WHERE player1 IN ($1,$2) AND player2 IN ($1,$2)
            GROUP BY player
        )
        SELECT * FROM players AS p
        LEFT OUTER JOIN cte_winners AS cw ON cw.player = p.id WHERE p.id IN ($1,$2)'
    USING player1_id,player2_id;
END;
$$ LANGUAGE plpgsql;    

3 个答案:

答案 0 :(得分:1)

如果您想选择<player1><player2>赢得的匹配,您可以使用此查询:

with cte_winners as (
    select
        id, case when winner then player1 else player2 end as player
    from public.matches
)
select *
from cte_winners
where player in (<player1>, <player2>)

<强>更新

获得所需的输出你可以使用这样的东西:

with cte_winners as (
    select
        case when winner then m.player1 else m.player2 end as player,
        count(*) as wins_v_opp,
        sum(count(*)) over() - count(*) as loses_v_opp
    from matches as m
    where player1 in (4200, 4201) and player2 in (4200, 4201)
    group by player
)
select *
from players as p
    left outer join cte_winners as cw on cw.player = p.id
where p.id in (4200, 4201)

<强> sql fiddle demo

<强> UPDATE2

with cte_player as (
    select p.id, p.name, p.wins, p.losses, p.rating
    from players as p
    where p.name in ('Sinku', 'Kenshiro')
), cte_winner as (
    select
        case when winner then m.player1 else m.player2 end as player,
        count(*) as wins_v_opp,
        sum(count(*)) over() - count(*) as loses_v_opp
    from matches as m
    where
        m.player1 in (select p.id from cte_player as p) and
        m.player2 in (select p.id from cte_player as p)
    group by player
)
select
    p.id, p.name, p.wins, p.losses, p.rating,
    m.wins_v_opp, m.loses_v_opp
from cte_player as p
    left outer join cte_winner as m on m.player = p.id

<强> sql fiddle demo

答案 1 :(得分:1)

SELECT id, name, wins, losses, rating
      ,count(CASE WHEN winner THEN m.player1 = p.id ELSE m.player2 = p.id END
             OR NULL) AS wins_v_opp
      ,count(CASE WHEN winner THEN m.player2 = p.id ELSE m.player1 = p.id END
             OR NULL) AS loses_v_opp
FROM  (
   SELECT  *, COALESCE(lag(p.id) OVER(), lead(p.id) OVER()) AS id2
   FROM    players p
   WHERE   p.name in ('Sinku', 'Kenshiro')
   ) p
JOIN matches m ON m.player1 IN (id, id2)
              AND m.player2 IN (id, id2)
GROUP BY 1,2,3,4,5;

- &GT; SQLfiddle

答案 2 :(得分:0)

select id
from public.matches
where player1 in ('<player1's number>','<player2's number>')
and player2 in ('<player1's number>','<player2's number>')

应该返回他们互相比赛的所有比赛和

select id
from public.matches
where (player1 = '<player1's number>' or player2 = '<player1's number>')
and (player1 = '<player2's number>' or player2 = '<player2's number>')
and winner = <condition that shows player1's wins>

返回假想的玩家1赢得的与假设玩家2的匹配。

因此获得评级看起来像

select ((
    select count(distinct id)
    from public.matches
    where (player1 = '<player1's number>' or player2 = '<player1's number>')
    and (player1 = '<player2's number>' or player2 = '<player2's number>')
    and winner = <condition that shows player1's wins>
) / (
    select id
    from public.matches
    where player1 in ('<player1's number>','<player2's number>')
    and player2 in ('<player1's number>','<player2's number>')
) * 100) as percent_of_player1_wins
from dual

请注意我使用的是PLSQL语法。