我有2个名为Players
和Teams
的表。大约有100行数据。
Players
列:Player_ID,Player_Name,Team_ID,Country_ID,Captain_ID,Matches_Played
Teams
列:Team_ID,Team_Name,Manager_ID,Matches_Won,Matches_Lost,Country_ID
Players
表:
--------------------------------------------------------------------------
| Player_ID Player_Name Team_Id Country_ID Captain_ID Matches_Played|
--------------------------------------------------------------------------
| 1 Ronaldo 1 1 1 250 |
| 2 Messi 2 2 2 220 |
| 3 Marcelo 1 1 1 185 |
| 4 Suarez 2 2 2 193 |
--------------------------------------------------------------------------
我希望使用 INNER JOIN 在每个团队中找到玩过最多游戏的玩家。
期望的结果:
--------------------------------------------------------------------------
| Player_ID Player_Name Team_Id Country_ID Captain_ID Matches_Played|
--------------------------------------------------------------------------
| 1 Ronaldo 1 1 1 250 |
| 2 Messi 2 2 2 220 |
--------------------------------------------------------------------------
我尝试使用的查询:
SELECT
p.Player_Name, t.Team_Name, src.Matches_Played AS Matches_Played
FROM
Players p
INNER JOIN
Teams t ON p.Team_ID = t.Team_ID
INNER JOIN
(SELECT Team_ID, MAX(Matches_Played) AS Matches_Played
FROM Players
GROUP BY Team_ID) src ON t.Team_ID = src.Team_ID
AND p.Team_ID = src.Team_ID;
此查询返回整个表格,每个玩家旁边的MAX
值Matches_Played
相同。
我如何修复查询以获得所需的结果?
答案 0 :(得分:3)
如果我理解你的问题,我想你可以尝试:
SELECT p.Player_Name, t.Team_Name, src.Matches_Played AS Matches_Played
FROM Players p
INNER JOIN Teams t
ON p.Team_ID = t.Team_ID
INNER JOIN (
SELECT Team_ID, MAX(Matches_Played) AS Matches_Played
FROM Players
GROUP BY Team_ID)src
ON p.Team_ID = src.Team_ID
AND p.Matches_Played = src.Matches_Played;
答案 1 :(得分:3)
你根本不需要加入来做这件事。从Sql Server 2005开始,有一个名为APPLY
运算符的东西可以更好地用于此查询:
SELECT p.Player_Name, t.Team_Name, p.Matches_Played
FROM Teams t
CROSS APPLY (
SELECT TOP 1 Player_Name, Matches_Played
FROM Players p
WHERE p.Team_ID = t.Team_ID
ORDER BY Matches_Played DESC
) p
但是如果这是一个由于某种原因需要使用JOIN的作业,则需要分两步完成。首先找到目标玩家的匹配数,然后获得该记录的完整行:
SELECT p.Player_Name, t.Team_Name, p.Matches_Played
FROM Teams t
INNER JOIN (
SELECT Team_ID, MAX(Matches_Played) as Max_Played
FROM Players
GROUP BY Team_ID
) played ON played.Team_ID = t.Team_ID
INNER JOIN Players p ON p.Team_ID = played.Team_ID AND p.Matches_Played = played.Max_Played
请注意,如果出现平局,这可能会显示每个团队不止一行,但问题并不能说明在这种情况下该怎么做。
另请注意,对于两个查询,我都是从Teams表而不是Players表开始的。查询优化器应该能够以任何一种方式解决它,但我认为对于这个查询来说,它使逻辑意义上的程序员开始考虑为每个团队记录找到匹配,特别是当我们看到{{1}时} option永远不会在查询的根目录中使用Players表。
最后,我怀疑还有第三个解决方案会使用窗口函数(有序的row_number + parition by),这可能会更好。
答案 2 :(得分:0)
我认为这种情况将是使用ROW_NUMBER的好地方。
基础数据:
CREATE TABLE #Players (Player_ID INT
,Player_Name VARCHAR(50)
,Team_ID INT
,Country_ID INT
,Captain_ID INT
,Matches_Played INT)
INSERT INTO #Players (Player_ID, Player_Name, Team_ID, Country_ID, Captain_ID, Matches_Played)
VALUES (1, 'Renaldo', 1, 1, 1, 250)
,(2, 'Messi', 2, 2, 2, 220)
,(3, 'Marcelo', 1, 1, 1, 185)
,(4, 'Suarez', 2, 2, 2, 193);
然后,我使用了一个基本的Select语句,并将其加入到另一个使用ROW_NUMBER()的select语句中
SELECT p.Player_ID
,p.Player_Name
,p.Team_ID
,p.Country_ID
,p.Captain_ID
,p.Matches_Played
FROM #Players p
INNER JOIN (SELECT Player_ID
,ROW_NUMBER() OVER (PARTITION BY Team_ID ORDER BY Matches_Played DESC) AS rnk
FROM #Players) AS p1 ON p1.Player_ID = p.Player_ID AND rnk = 1
这是使用ROW_NUMBER()为团队中的每个球员分配位置。如果您在同一支球队中有5名球员,它将以1到5的顺序排列,其中1场比赛最多,5场最少。然后,当您在rnk = 1上加入时,您只会加入每个团队中最多玩游戏的玩家。
如果这会让您感到困惑,则可以将语句放入JOIN中,也可以采用其他方法。
具有CTE(公用表表达式):
WITH CTE (Player_ID, Rnk) AS
(SELECT Player_ID
,ROW_NUMBER() OVER (PARTITION BY Team_ID ORDER BY Matches_Played DESC)
FROM #Players)
SELECT p.Player_ID
,p.Player_Name
,p.Team_ID
,p.Country_ID
,p.Captain_ID
,p.Matches_Played
FROM #Players p
INNER JOIN CTE ON cte.Player_ID = p.Player_ID AND rnk = 1
带有临时表:
SELECT Player_ID
,ROW_NUMBER() OVER (PARTITION BY Team_ID ORDER BY Matches_Played DESC) AS rnk
INTO #RankTable
FROM #Players
SELECT p.Player_ID
,p.Player_Name
,p.Team_ID
,p.Country_ID
,p.Captain_ID
,p.Matches_Played
FROM #Players p
INNER JOIN #RankTable r ON r.Player_ID = p.Player_ID AND rnk = 1