sql Server:按点数和按排名顺序排列

时间:2013-06-23 20:49:40

标签: sql-server

我有一个包含以下字段的游戏桌:

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

我可以获得排名,积分和平均点数,但获得最后输入的名称,我认为需要再次加入同一张表,这似乎有点不对。

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

5 个答案:

答案 0 :(得分:5)

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

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

小提琴中的

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

答案 1 :(得分:3)

您可以从SQL-Server 2005向上使用Ranking Functions

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

请注意,结果是不同的,因为我显示的是具有最高点的行,以防电子邮件不唯一,因此“测试”而不是“Bob”。

答案 2 :(得分: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;

答案 3 :(得分: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

答案 4 :(得分: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()之间进行选择。

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