2010-06-22 8 views
3

J'ai une table appelée Jeux avec colonnes: Player1Id, Player2Id, Player1Points, Player2Points.Somme complexe avec regroupement

données Exemple:

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

Et je veux avoir une liste avec la somme de points pour chaque joueur, comme ça:

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

Comment achive que dans SQL (SQL Server 2008) ? Et si j'ai besoin d'une somme de points seulement si un joueur a gagné un match? Peut-il être fait sans utiliser de variables, de boucles, etc.?

Répondre

2
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 

Rendement:

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

La requête sera encore plus compliqué si vous ajoutez plus de joueurs. Il serait préférable d'enregistrer le score pour chaque joueur sur une rangée distincte. Vous pouvez ajouter une colonne pour désigner le jeu.

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

Votre requête serait alors simple:

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

Cela devrait être 'UNION ALL' (si John a marqué 3 en deux matches, il ne sera compté qu'une seule fois) – Quassnoi

+0

@Quassnoi, fixe, merci! –

3

Je serais tenté de réorganiser les données, peut-être:

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

etc

+0

De plus, si vous commencez à avoir des jeux avec 3 joueurs, vous n'avez pas besoin d'ajouter des colonnes. + 1 pour suggérer la normalisation des données. – HLGEM

0

tables de test:

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; 

Somme 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; 

Somme Points de jeux gagnés:

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; 

Différence:

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; 
1

Cela comptera seulement les scores de victoire:

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 
1

Pour répondre à votre deuxième question, vous pouvez alors modifier la réponse de Marcus à ceci:

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 

Selon la façon dont vous voulez gérer les liens, vous devez changer la> =.