6

我有一个包含这些字段的游戏桌:

ID    Name       Email      Points
----------------------------------
1     John     john@aaa.com    120
2     Test     bob@aaa.com     100
3     John     john@bbb.com    80
4     Bob      bob@aaa.com     50
5     John     john@aaa.com    80

我想通过电子邮件对它们进行分组(电子邮件表明无论第 2 行和第 4 行有不同的名称,两个玩家都是相同的),并且在结果中也有总和和最后输入的名称,并以最高的总和对他们进行排名到最低

我想从示例表中得到的结果是:

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

我可以实现排名、总分和平均分,但是我认为最后输入的名字需要再次加入同一张表,这似乎有点不对劲。

任何想法如何做到这一点?

4

5 回答 5

6

显示名称和分组是电子邮件将导致使用例如 MIN(Name) 并导致重复名称。

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

Fiddle 中有两条注释行,您应该取消注释以查看相同结果的行为。

于 2013-06-23T21:12:04.267 回答
3

您可以Ranking Functions从 SQL-Server 2005 开始使用:

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;

演示

请注意,结果是不同的,因为如果电子邮件不是唯一的,我会显示最高点的行,因此“测试”而不是“鲍勃”。

于 2013-06-23T21:17:37.423 回答
2

以下是 SQL Server 2012+、2005 到 2008 R2 和 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', 'john@aaa.com', 120)
    , (2, 'Test', 'bob@aaa.com', 100)
    , (3, 'John', 'john@bbb.com', 80)
    , (4, 'Bob', 'bob@aaa.com', 50)
    , (5, 'John', 'john@aaa.com', 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 至 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', 'john@aaa.com', 120)
    , (2, 'Test', 'bob@aaa.com', 100)
    , (3, 'John', 'john@bbb.com', 80)
    , (4, 'Bob', 'bob@aaa.com', 50)
    , (5, 'John', 'john@aaa.com', 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;

2000

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', 'john@aaa.com', 120
UNION ALL
SELECT 2, 'Test', 'bob@aaa.com', 100
UNION ALL
SELECT  3, 'John', 'john@bbb.com', 80
UNION ALL
SELECT 4, 'Bob', 'bob@aaa.com', 50
UNION ALL
SELECT 5, 'John', 'john@aaa.com', 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;
于 2013-06-23T21:27:57.617 回答
0

我认为这就是你需要的

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

这是一个SQL Fiddle

于 2013-06-23T21:00:27.980 回答
0

只有@RegisteredUser 的解决方案似乎可以处理name. 但是,它需要 SQL Server 2012,所以这里有一个更通用的解决方案:

      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;

您在问题中没有足够的信息来选择rank()dense_rank()

此外,这个版本相对于其他版本更简单,因为您可以混合使用窗口函数和聚合函数。

于 2013-06-23T23:02:42.623 回答