2013-06-23 13 views
5

Mam tabeli gier z tych pól:SQL Server: Rank przez sumę punktów i porządku przez Ranking

ID Name  Email  Points 
---------------------------------- 
1  John  [email protected] 120 
2  Test  [email protected]  100 
3  John  [email protected] 80 
4  Bob  [email protected]  50 
5  John  [email protected] 80 

Chcę grupować je pocztą elektroniczną (e-mail Określa, że ​​obaj gracze są takie same bez względu na to, że wiersz 2 i 4 mają różne nazwy), a także sumę punktów i nazwisko wpisane w wynikach i pozycjonowanie je z heighest suma punktów do najniższego

wynik chcę od stołu próbki wynosi:

Ranking  Name  Points Games_Played  Average_Points 
------------------------------------------------------------------------------------------ 
1   John  200   2    100 
2   Bob   150   2    75 
3   John  80   1    80 

Mogę osiągnąć pozycję w rankingu, sumę punktów i średnich punktów, ale otrzymanie ostatniej wpisanej nazwy wymaga ponownego połączenia z tym samym stołem i wydaje się trochę nie tak.

Jakieś pomysły, jak to zrobić?

Odpowiedz

4

Wyświetlenie nazwy i grupowanie jako e-mail spowoduje użycie np. MIN (imię i nazwisko) i prowadzić do zduplikowanych nazw.

Select Rank() over (order by Points desc) as Rank 
,Name,Points,Games_Played,Average_Points 
from 
(
Select Min(Name) as Name,Email,Sum(Points) as Points 
,Count(*) as Games_Played,AVG(Points) as Average_Points 
From @a Group by Email 
) a 
order by Rank 

SQLFiddle

w Fiddle to dwie linie z komentarzem należy Odkomentuj zobaczyć zachowanie na identycznych rezultatów.

+0

Bajeczna odpowiedź. Dzięki ..... rozwiązałem mój problem i nauczyłem się nowych rzeczy. czy nie powinien to być Max (nazwa)? co oznacza Min (imię)? –

+0

Użyłbym adresu e-mail, aby jasno i pominąć nazwę, to zależy od ciebie, używając minimalnej lub maksymalnej nazwy, w każdym razie jest to rodzaj losowy. – bummi

+0

well Po prostu chcę wiedzieć, jaka jest funkcjonalność Max lub Min dla nazwy, ponieważ nie jest liczbą, czy działa tak, jak zamawianie słownika? –

0

myślę, że to jest to, czego potrzebujesz

select ROW_NUMBER() OVER (ORDER BY sum(r1.points) Desc) as Ranking, 
    r1.name as Name, 
    sum(r1.points) as Points, 
    r3.gplayed as 'Games Played', 
    r2.points 'Average Points' 
from ranks r1 
    join (select avg(points) as points, email from ranks group by email) r2 
     on r1.email = r2.email 
    join (select email, count(*) as gplayed from ranks group by email) r3 
     on r1.email = r3.email 
group by 
    r1.email, 
    r1.name, 
    r2.points, 
    r3.gplayed 

Oto SQL Fiddle.

3

Można użyć Ranking Functions z SQL Server 2005 wzwyż:

WITH Points 
    AS (SELECT Sum_Points = Sum(points) OVER ( 
           partition BY email), 
       Games_Played = Count(ID) OVER ( 
           partition BY email), 
       Average_Points = AVG(Points) OVER ( 
           partition BY email), 
       Rank = DENSE_RANK() OVER ( 
           Partition BY email Order By Points DESC), 
       * 
     FROM dbo.Game) 
SELECT Ranking=DENSE_RANK()OVER(ORDER BY Sum_Points DESC), 
     Name, 
     Points=Sum_Points, 
     Games_Played, 
     Average_Points 
FROM Points 
WHERE Rank = 1 
Order By Sum_Points DESC; 

DEMO

Należy pamiętać, że wynik jest inny, ponieważ jestem pokazując wiersz z najwyższego punktu w przypadku, gdy e-mail jest nie jest unikalny, więc "Testuj" zamiast "Bob".

2

Poniżej znajdują się oddzielne rozwiązania dla SQL Server 2012+, 2005 do 2008 R2 i 2000:

2012+

CREATE TABLE #PlayerPoints 
    (ID INT PRIMARY KEY 
    , Name VARCHAR(10) NOT NULL 
    , Email VARCHAR(20) NOT NULL 
    , Points INT NOT NULL); 

INSERT INTO #PlayerPoints (ID, Name, Email, Points) 
VALUES 
     (1, 'John', '[email protected]', 120) 
    , (2, 'Test', '[email protected]', 100) 
    , (3, 'John', '[email protected]', 80) 
    , (4, 'Bob', '[email protected]', 50) 
    , (5, 'John', '[email protected]', 80) 

WITH BaseData 
AS 
    (SELECT ID 
     , Email 
     , Points 
     , LastRecordName = LAST_VALUE(Name) OVER 
      (PARTITION BY Email 
      ORDER BY ID DESC 
      ROWS UNBOUNDED PRECEDING) 
    FROM #PlayerPoints) 
SELECT Email 
    , LastRecordName = MAX(LastRecordName) 
    , Points = SUM(Points) 
    , Games_Played = COUNT(*) 
    , Average_Points = AVG(Points) 
FROM BaseData 
GROUP BY Email 
ORDER BY Points DESC; 

2005 do 2008 R2

CREATE TABLE #PlayerPoints 
    (ID INT PRIMARY KEY 
    , Name VARCHAR(10) NOT NULL 
    , Email VARCHAR(20) NOT NULL 
    , Points INT NOT NULL); 

INSERT INTO #PlayerPoints (ID, Name, Email, Points) 
VALUES 
     (1, 'John', '[email protected]', 120) 
    , (2, 'Test', '[email protected]', 100) 
    , (3, 'John', '[email protected]', 80) 
    , (4, 'Bob', '[email protected]', 50) 
    , (5, 'John', '[email protected]', 80) 

WITH BaseData 
AS 
    (SELECT ID 
     , Email 
     , Name 
     , ReverseOrder = ROW_NUMBER() OVER 
      (PARTITION BY Email 
      ORDER BY ID DESC) 
    FROM #PlayerPoints) 
SELECT pp.Email 
    , LastRecordName = MAX(bd.Name) 
    , Points = SUM(pp.Points) 
    , Games_Played = COUNT(*) 
    , Average_Points = AVG(pp.Points) 
FROM #PlayerPoints pp 
JOIN BaseData bd 
    ON pp.Email = bd.Email 
    AND bd.ReverseOrder = 1 
GROUP BY pp.Email 
ORDER BY Points DESC; 

CREATE TABLE #PlayerPoints 
    (ID INT PRIMARY KEY 
    , Name VARCHAR(10) NOT NULL 
    , Email VARCHAR(20) NOT NULL 
    , Points INT NOT NULL); 

INSERT INTO #PlayerPoints (ID, Name, Email, Points) 
SELECT 1, 'John', '[email protected]', 120 
UNION ALL 
SELECT 2, 'Test', '[email protected]', 100 
UNION ALL 
SELECT 3, 'John', '[email protected]', 80 
UNION ALL 
SELECT 4, 'Bob', '[email protected]', 50 
UNION ALL 
SELECT 5, 'John', '[email protected]', 80; 

SELECT pp.Email 
    , LastRecordName = MAX(sppmi.Name) 
    , Points = SUM(pp.Points) 
    , Games_Played = COUNT(*) 
    , Average_Points = AVG(pp.Points) 
FROM #PlayerPoints pp 
JOIN 
    (SELECT spp.Email 
     , spp.Name 
    FROM #PlayerPoints spp 
    JOIN 
     (SELECT Email 
      , MaximumID = MAX(ID) 
     FROM #PlayerPoints 
     GROUP BY Email) mi 
     ON spp.ID = mi.MaximumID) sppmi 
    ON pp.Email = sppmi.Email 
GROUP BY pp.Email 
ORDER BY Points DESC; 
+0

+1. . . Twoje jest jedynym rozwiązaniem, które poprawnie obsługuje faktyczne ograniczenie na nazwę. Myślę, że rozwiązanie jest ograniczone, polegając na funkcji dostępnej tylko w SQL Server 2012, gdy nie jest to określone w OP. –

+0

Dodam również rozwiązanie 2005+. –

+0

I dodano 2000 rozwiązanie. –

0

Tylko rozwiązanie z @RegisteredUser wydaje się obsługiwać ograniczenie na name. Wymaga to jednak SQL Server 2012, więc tutaj jest bardziej ogólne rozwiązanie:

 Select dense_rank() over (order by sum(points) desc) as ranking 
      max(case when islastid = 1 then Name end) as Name, Email, Sum(Points) as Points, 
      Count(*) as Games_Played, AVG(Points) as Average_Points 
     From (select g.*, 
        row_number() over (partition by email order by id desc) as islastid 
      from games g 
      ) t 
     Group by Email; 

Nie masz wystarczających informacji w kwestii wyboru między rank() i dense_rank().

Ta wersja jest również prostsza w porównaniu z innymi wersjami, ponieważ można mieszać funkcje okna i funkcje agregacji.

Powiązane problemy