我有一个包含以下字段的游戏桌:
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
我可以获得排名,积分和平均点数,但获得最后输入的名称,我认为需要再次加入同一张表,这似乎有点不对。
任何想法如何做到这一点?
答案 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
小提琴中的是两条注释行,您应该取消注释以查看相同结果的行为。
答案 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;
请注意,结果是不同的,因为我显示的是具有最高点的行,以防电子邮件不唯一,因此“测试”而不是“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()
之间进行选择。
此外,相对于其他版本,此版本更简单,因为您可以混合窗口函数和聚合函数。