2013-10-22 144 views
0

所以我有两个表,播放机和结构,像这样匹配:汇总总计给出多个条件

     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 | 

在哪里,如果PLAYER1赢得了那场比赛,或者如果player2假的赢家是真实的赢得了比赛。

使用球员表进行简单的赢/输比较很简单,但我正在观察比较两名球员相互面对对手的情况,以及他们对对方的记录。

所以我对我怎么会总结困惑,其中给出一个给定的球员可能被列为要么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;  

回答

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>) 

update

,从而获得所需的输出你可以使用这样的事情:

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

+0

我就更新了原来的职位:) – OverlordQ

+0

@OverlordQ您的评论还没有完成:) –

+0

现在$ 10,000的问题是,如果我不知道前面的玩家ID我想按名称选择,我不需要加入CTE的球员吗? – OverlordQ

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> 

返回一个假想的PLAYER1赢得了对一个假设player2比赛。

因此得到一个得分看起来像

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语法。

+0

我已经计算好了收视率,我想看看是否有一个查询可以返回我存储的数据(胜,输,等级)以及两个额外的栏目,详细列出两名球员之间的比赛。 – OverlordQ

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; 

- >SQLfiddle

+0

这不需要是左手,所以即使他们还没有匹配,我仍然会返回他们的W/L /等级记录吗?改变了模式,并以[this]结尾(http://sqlfiddle.com/#!12/f92bb/1/0) – OverlordQ

+0

@OverlordQ:没错。如果你愿意的话,可以把'LEFT'加到'JOIN'上。 –