开发者

Complex sum with grouping

I have table called Games with columns: Player1Id, Player2Id, Player1Points, Player2Points.

Sample dat开发者_JAVA百科a:

Player1Id    Player2Id    Player1Points    Player2Points
---------    ---------    -------------    -------------
John         Piter        4                 1
John         Adam         2                10
Piter        Adam         4                 2

And I want to have a list with sum of points for each player, like that:

PlayerId    Points
--------    ------
John         6
Piter        5
Adam        12

How to achive that in SQL (SQL Server 2008)? And what if I need a sum of points only if some player won a match? Can it be done without using variables, loops etc?


I'd be tempted to reorganise the data, perhaps:

Gameid Player Score
  1    John     4
  2    John     2
  1    Piter    1

etc


SELECT Player1Id AS PlayerId, SUM(Player1Points) AS Points FROM
(SELECT Player1Id, Player1Points FROM MyTable
UNION ALL
SELECT Player2Id, Player2Points FROM MyTable) t1
GROUP BY Player1Id
ORDER BY Player1Id

Yields:

PlayerId       Points
--------       ------
Adam               12
John                6
Piter               5

The query will get even more complicated if you add more players. It would be best to record the score for each player on a distinct row. You could add a column to designate the game.

PlayerId   Points   GameId
--------   ------   ------
John            4        1
Piter           1        1
John            2        2
Adam           10        2
Piter           4        3
Adam            2        3

Your query would then be simple:

SELECT PlayerId, SUM(Points)
FROM MyTable
GROUP BY PlayerId
ORDER BY PlayerId


This will count only victory scores:

SELECT  player, SUM(score) AS score
FROM    (
        SELECT  player1id AS player, player1points AS score
        FROM    mytable
        WHERE   player1points > player2points
        UNION ALL
        SELECT  player2id, player2points
        FROM    mytable
        WHERE   player2points > player1points
        ) q
GROUP BY
        player


To answer your second question, you could then alter Marcus' answer to this:

SELECT
    Player1Id,
    SUM(Player1Points)
FROM
(
    SELECT Player1Id, Player1Points FROM MyTable WHERE Player1Points >= Player2Points
    UNION ALL
    SELECT Player2Id, Player2Points FROM MyTable WHERE Player2Points >= Player1Points
) t1
GROUP BY
    Player1Id

Depending on how you want to handle ties, you would need to change the >=.


Test tables:

DECLARE @Table TABLE (Player1Id VARCHAR(17), Player2Id VARCHAR(17), Player1Points INT, Player2Points INT);
INSERT INTO @Table
    SELECT 'John', 'Piter', 4, 1 UNION ALL
    SELECT 'John', 'Adam', 2, 10 UNION ALL
    SELECT 'Piter', 'Adam', 4, 2;

Sum Points:

WITH CTE (PlayerId, Points) AS (
    SELECT Player1Id, Player1Points FROM @Table
     UNION ALL
    SELECT Player2Id, Player2Points FROM @Table
)
SELECT PlayerId, SUM(Points) FROM CTE GROUP BY PlayerId;

Sum Points from won games:

WITH CTE (PlayerId, Points, Won) AS (
    SELECT Player1Id, Player1Points, CASE WHEN Player1Points > Player2Points THEN 1 ELSE 0 END FROM @Table
     UNION ALL
    SELECT Player2Id, Player2Points, CASE WHEN Player2Points > Player1Points THEN 1 ELSE 0 END FROM @Table
)
SELECT PlayerId, SUM(Points) FROM CTE WHERE Won = 1 GROUP BY PlayerId;

Difference:

WITH CTE (PlayerId, Points) AS (
    SELECT Player1Id, CASE WHEN Player1Points > Player2Points THEN Player1Points - Player2Points ELSE (Player2Points - Player1Points) * -1 END FROM @Table
     UNION ALL
    SELECT Player2Id, CASE WHEN Player2Points > Player1Points THEN Player2Points - Player1Points ELSE (Player1Points - Player2Points) * -1 END FROM @Table
)
SELECT PlayerId, SUM(Points) FROM CTE GROUP BY PlayerId;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜