2013-06-23 42 views
5

我有一个游戏桌与这些领域:SQL SERVER:排名由点和秩序的总和排名

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 

我想他们组通过电子邮件(电子邮箱标识,这两个球员都是一样的,不管是行2和4有不同的名称),并有同样的结果点的总和,最后输入的名称,并点到最低

的heighest总和进行排名,我从样品台想要的结果是:

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

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

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

回答

4

显示名称和分组是电子邮件将导致使用例如, 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

在小提琴

两个评论,你应该取消注释上看到相同的结果的行为线。

+0

绝妙的回答。谢谢.....解决了我的问题,并学习了一些新的东西。不应该是Max(姓名)? Min(姓名)的含义是什么? –

+0

我会使用电子邮件清楚地忽略名称,这取决于您使用MININimum或MAXimum名称,它在任何情况下都是随机的。 – bummi

+0

以及我只是想知道什么是Max或Min的名称作为它不是一个数字的功能,它是否像字典顺序工作? –

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

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; 

DEMO

注意,结果是不同的,因为我在展示用的情况下的最高点行的电子邮件不是唯一的,所以“测试”而不是“鲍勃”。

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', '[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年至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。 。 。您是唯一正确处理名称实际约束的解决方案。我认为解决方案是有限的,依赖于仅在SQL Server 2012中可用的函数,而在OP中未指定该函数。 –

+0

我还会添加2005+解决方案。 –

+0

并添加了2000解决方案。 –

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()之间做出选择。

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