使用 Sql 查询在足球数据库中查找复出
Find Comebacks in Football Database With Sql Query
我有 4 张桌子。
匹配:
| id | HomeTeamID | AwayTeamID |
--------|-------------|------------
| 1 | 1 | 2
| 2 | 1 | 3
| 3 | 3 | 1
目标:
| id | MatchID | Minute | TeamID
--------|-------------|---------- |---------
| 1 | 1 | 3 | 2
| 2 | 1 | 5 | 1
| 3 | 1 | 15 | 1
| 4 | 2 | 43 | 3
| 5 | 2 | 75 | 1
| 6 | 2 | 85 | 1
| 7 | 3 | 11 | 1
| 8 | 3 | 13 | 3
| 9 | 3 | 77 | 3
团队:
| id | Name |
--------|-------------|
| 1 | Chelsea |
| 2 | Arsenal |
| 3 | Tottenham |
经理:
| id | Name | TeamID |
--------|-------------|-------------
| 1 | Conte | 1
| 2 | Wenger | 2
| 3 | Pochettino | 3
我想获得经理复出比赛的次数。例如,孔蒂的球队在第一场和第二场比赛中率先失球,但他们赢了。所以孔蒂有2次翻盘。波切蒂诺在第 3 场比赛中有 1 次翻盘。我想通过 SQL 查询找到它。
我找到了每支球队比赛的第一个进球。但是经过一些步骤后,我失去了我正在做的事情。
SELECT MatchID, MIN(minute), g.TeamID
FROM Goals g
JOIN Managers m ON m.TeamID = g.TeamID
GROUP BY MatchID, g.TeamID
我不太关注足球,但假设翻盘是指球队先失一球但随后赢得比赛,我会使用以下逻辑来得出结果。
首先,我们需要在一场比赛中率先失球的球队:
SELECT TeamID, MatchID FROM Goals WHERE GoalID in
(SELECT Min(GoalID) FROM Goals GROUP BY MatchID)
其次,对于每场比赛,我们需要取得第一个进球的球队继续获胜的比赛。
SELECT MatchID FROM
(SELECT COUNT(GoalID) as TotalGoals, MatchID FROM Goals GROUP BY MatchID) AS MatchSummary
INNER JOIN
(SELECT COUNT(GoalID) as TeamGoals, MatchID FROM
(SELECT TeamID, MatchID FROM Goals WHERE GoalID in
(SELECT Min(GoalID) FROM Goals GROUP BY MatchID)
) as GoalsOfTheTeamThatConcededFirstGoal
GROUP BY MatchID) as SummaryOfTeamThatConcededFirstGoal
ON MatchSummary.MatchID = SummaryOfTeamThatConcededFirstGoal.MatchID
WHERE (TotalGoals - TeamGoals) < TeamGoals
结合这两个查询,您将能够获得卷土重来的球队的 TeamID。
我认为使用游标或临时表可以更好地完成这项任务,但我想让答案尽可能简单。因此我避免了它。您绝对应该探索这两种方法。
with cte
(
MatchID,TeamID,TotalGoalTime,NoOfGoals,ManagerName,comeback)
as(SELECT MatchID, g.TeamID,sum(minutea) as'TotalGoalTime' ,count(*)as'NoOfGoals',m.name as'ManagerName'
,comeback =ROW_NUMBER() OVER(PARTITION BY MatchID order by sum(minutea) desc)
FROM Goals g
JOIN Managers m ON m.TeamID = g.TeamID
join [Teams] t on t.Id=g.TeamId
GROUP BY MatchID, g.TeamID,m.name )
Select MatchID,TeamID,NoOfGoals,ManagerName from cte where comeback =1
以上查询现在为我们提供了整体回归,将更新回归的数量。
如果你想计算足球比赛中的每一次翻盘,你可以使用下面的解决方案。那么翻盘的定义就是球队输球后每多进一球。例如,对于以下场景,我们有三个翻盘:
Team A Team B
0 - 1 //team b scores
1 - 1 //team a scores
2 - 1 //team a scores (comeback for a)
2 - 2 //team b scores
2 - 3 //team b scores (comeback for b)
3 - 3 //team a scores
4 - 3 //team a scores (comeback for a)
从上面看来我们翻盘了,当比分发生变化时,和之前的比分持平。我正在使用 SUM with OVER 和 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
按 minute
排序,以便在每次进球时计算得分。
这是完整的工作示例:
DECLARE @matches TABLE
(
[id] TINYINT
,[HomeTeamID] TINYINT
,[AwayTeamID] TINYINT
);
DECLARE @Goals TABLE
(
[id] TINYINT
,[MatchID] TINYINT
,[Minute] TINYINT
,[TeamID] TINYINT
);
DECLARE @Teams TABLE
(
[id] TINYINT
,[Name] VARCHAR(12)
);
DECLARE @Managers TABLE
(
[Id] TINYINT
,[Name] VARCHAR(12)
,[TeamID] TINYINT
);
INSERT INTO @matches ([id], [HomeTeamID], [AwayTeamID])
VALUES (1, 1, 2)
,(2, 1, 3)
,(3, 3, 1)
,(4, 1, 4);
INSERT INTO @Goals ([id], [MatchID], [Minute], [TeamID])
VALUES (1, 1, 3, 2)
,(2, 1, 5, 1)
,(3, 1, 15, 1)
,(4, 2, 43, 3)
,(5, 2, 75, 1)
,(6, 2, 85, 1)
,(7, 3, 11, 1)
,(8, 3, 13, 3)
,(9, 3, 77, 3)
,(10, 4, 3, 1)
,(11, 4, 5, 4)
,(12, 4, 10, 4)
,(13, 4, 12, 1)
,(14, 4, 25, 1)
,(15, 4, 46, 4)
,(16, 4, 60, 4)
,(17, 4, 72, 4)
,(18, 4, 84, 4);
INSERT INTO @Teams ([id], [Name])
VALUES (1, 'Chelsea')
,(2, 'Arsenal')
,(3, 'Tottenham')
,(4, 'Real Madrid');
INSERT INTO @Managers ([Id], [Name], [TeamID])
VALUES (1, 'Conte', 1)
,(2, 'Wenger', 2)
,(3, 'Pochettino', 3)
,(4, 'Zidane', 4);
WITH DataSource AS
(
SELECT m.[id]
,m.[HomeTeamID]
,m.[AwayTeamID]
,ROW_NUMBER() OVER (PARTITION BY m.[id] ORDER BY g.[minute]) AS [EventID]
,IIF
(
SUM(IIF(m.[HomeTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - 1
=
SUM(IIF(m.[AwayTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
OR
SUM(IIF(m.[HomeTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
=
SUM(IIF(m.[AwayTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1
,IIF(m.[HomeTeamID] = g.[teamID], 'H', 'A') -- (H)ome come back, (A)way come ba
,'N' -- no come back
) AS [ComeBack]
FROM @matches m
INNER JOIN @Goals g
ON m.[id] = g.[MatchID]
)
SELECT T.[Name]
FROM DataSource DS
INNER JOIN @Teams T
ON IIF([ComeBack] = 'H', [HomeTeamID], [AwayTeamID]) = T.[id]
WHERE DS.[EventID] <> 1
AND DS.[ComeBack] <> 'N';
以上将为我们提供:
Chelsea
Chelsea
Chelsea
Tottenham
Real Madrid
Real Madrid
注意,我又添加了一场比赛来证明这一点。
这里"Comeback"表示球队先失球,但球队赢了这场比赛。
我使用 2 个通用子查询,1) winners
,其中包含每个未以平局结束的游戏的 MatchID
和 TeamID
。和 2) first_goals
,其中包含那些 TeamID
,它们在比赛中打进了第一个进球。
因此,使用以下方式连接这些子查询:
on winners.MatchID = first_goals.MatchID and winners.TeamID <> first_goals.TeamID
为我们提供了那些球队获胜但未取得第一个进球的比赛(即 "Comeback")。
最后我们对 Teams
和 Managers
表使用简单连接:
with Goals(id , MatchID , Minute ,TeamID) as (
select 1 , 1 , 3 , 2 union all
select 2 , 1 , 5 , 1 union all
select 3 , 1 , 15 , 1 union all
select 4 , 2 , 43 , 3 union all
select 5 , 2 , 75 , 1 union all
select 6 , 2 , 85 , 1 union all
select 7 , 3 , 11 , 1 union all
select 8 , 3 , 13 , 3 union all
select 9 , 3 , 77 , 3
),
Teams (id, Name) as(
select 1 ,'Chelsea' union all
select 2 ,'Arsenal' union all
select 3 ,'Tottenham'
),
Managers(id, Name, TeamID) as (
select 1 ,'Conte', 1 union all
select 2 ,'Wenger', 2 union all
select 3 ,'Pochettino', 3
)
select winners.TeamID, winners.MatchID, Teams.Name, Managers.Name from (
select t1.* from
(
select TeamID, MatchID, count(*) as goal_scored from Goals
group by TeamID, MatchID
)t1
inner join
(
select MatchID, max(goal_scored) as winner_goals_cnt from (
select TeamID, MatchID, count(*) as goal_scored from Goals
group by TeamID, MatchID
)t
group by MatchID
having min(goal_scored) <> max(goal_scored)
)t2
on t1.MatchID = t2.MatchID and t1.goal_scored = t2.winner_goals_cnt
) winners
inner join
(
select * from (
select Goals.*, row_number() over(partition by MatchID order by Minute, id) rn from Goals
) f
where rn = 1
) first_goals
on winners.MatchID = first_goals.MatchID and winners.TeamID <> first_goals.TeamID
inner join Teams
on winners.TeamID = Teams.id
inner join Managers
on winners.TeamID = Managers.TeamID
我有 4 张桌子。
匹配:
| id | HomeTeamID | AwayTeamID |
--------|-------------|------------
| 1 | 1 | 2
| 2 | 1 | 3
| 3 | 3 | 1
目标:
| id | MatchID | Minute | TeamID
--------|-------------|---------- |---------
| 1 | 1 | 3 | 2
| 2 | 1 | 5 | 1
| 3 | 1 | 15 | 1
| 4 | 2 | 43 | 3
| 5 | 2 | 75 | 1
| 6 | 2 | 85 | 1
| 7 | 3 | 11 | 1
| 8 | 3 | 13 | 3
| 9 | 3 | 77 | 3
团队:
| id | Name |
--------|-------------|
| 1 | Chelsea |
| 2 | Arsenal |
| 3 | Tottenham |
经理:
| id | Name | TeamID |
--------|-------------|-------------
| 1 | Conte | 1
| 2 | Wenger | 2
| 3 | Pochettino | 3
我想获得经理复出比赛的次数。例如,孔蒂的球队在第一场和第二场比赛中率先失球,但他们赢了。所以孔蒂有2次翻盘。波切蒂诺在第 3 场比赛中有 1 次翻盘。我想通过 SQL 查询找到它。
我找到了每支球队比赛的第一个进球。但是经过一些步骤后,我失去了我正在做的事情。
SELECT MatchID, MIN(minute), g.TeamID
FROM Goals g
JOIN Managers m ON m.TeamID = g.TeamID
GROUP BY MatchID, g.TeamID
我不太关注足球,但假设翻盘是指球队先失一球但随后赢得比赛,我会使用以下逻辑来得出结果。
首先,我们需要在一场比赛中率先失球的球队:
SELECT TeamID, MatchID FROM Goals WHERE GoalID in
(SELECT Min(GoalID) FROM Goals GROUP BY MatchID)
其次,对于每场比赛,我们需要取得第一个进球的球队继续获胜的比赛。
SELECT MatchID FROM
(SELECT COUNT(GoalID) as TotalGoals, MatchID FROM Goals GROUP BY MatchID) AS MatchSummary
INNER JOIN
(SELECT COUNT(GoalID) as TeamGoals, MatchID FROM
(SELECT TeamID, MatchID FROM Goals WHERE GoalID in
(SELECT Min(GoalID) FROM Goals GROUP BY MatchID)
) as GoalsOfTheTeamThatConcededFirstGoal
GROUP BY MatchID) as SummaryOfTeamThatConcededFirstGoal
ON MatchSummary.MatchID = SummaryOfTeamThatConcededFirstGoal.MatchID
WHERE (TotalGoals - TeamGoals) < TeamGoals
结合这两个查询,您将能够获得卷土重来的球队的 TeamID。
我认为使用游标或临时表可以更好地完成这项任务,但我想让答案尽可能简单。因此我避免了它。您绝对应该探索这两种方法。
with cte
(
MatchID,TeamID,TotalGoalTime,NoOfGoals,ManagerName,comeback)
as(SELECT MatchID, g.TeamID,sum(minutea) as'TotalGoalTime' ,count(*)as'NoOfGoals',m.name as'ManagerName'
,comeback =ROW_NUMBER() OVER(PARTITION BY MatchID order by sum(minutea) desc)
FROM Goals g
JOIN Managers m ON m.TeamID = g.TeamID
join [Teams] t on t.Id=g.TeamId
GROUP BY MatchID, g.TeamID,m.name )
Select MatchID,TeamID,NoOfGoals,ManagerName from cte where comeback =1
以上查询现在为我们提供了整体回归,将更新回归的数量。
如果你想计算足球比赛中的每一次翻盘,你可以使用下面的解决方案。那么翻盘的定义就是球队输球后每多进一球。例如,对于以下场景,我们有三个翻盘:
Team A Team B
0 - 1 //team b scores
1 - 1 //team a scores
2 - 1 //team a scores (comeback for a)
2 - 2 //team b scores
2 - 3 //team b scores (comeback for b)
3 - 3 //team a scores
4 - 3 //team a scores (comeback for a)
从上面看来我们翻盘了,当比分发生变化时,和之前的比分持平。我正在使用 SUM with OVER 和 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
按 minute
排序,以便在每次进球时计算得分。
这是完整的工作示例:
DECLARE @matches TABLE
(
[id] TINYINT
,[HomeTeamID] TINYINT
,[AwayTeamID] TINYINT
);
DECLARE @Goals TABLE
(
[id] TINYINT
,[MatchID] TINYINT
,[Minute] TINYINT
,[TeamID] TINYINT
);
DECLARE @Teams TABLE
(
[id] TINYINT
,[Name] VARCHAR(12)
);
DECLARE @Managers TABLE
(
[Id] TINYINT
,[Name] VARCHAR(12)
,[TeamID] TINYINT
);
INSERT INTO @matches ([id], [HomeTeamID], [AwayTeamID])
VALUES (1, 1, 2)
,(2, 1, 3)
,(3, 3, 1)
,(4, 1, 4);
INSERT INTO @Goals ([id], [MatchID], [Minute], [TeamID])
VALUES (1, 1, 3, 2)
,(2, 1, 5, 1)
,(3, 1, 15, 1)
,(4, 2, 43, 3)
,(5, 2, 75, 1)
,(6, 2, 85, 1)
,(7, 3, 11, 1)
,(8, 3, 13, 3)
,(9, 3, 77, 3)
,(10, 4, 3, 1)
,(11, 4, 5, 4)
,(12, 4, 10, 4)
,(13, 4, 12, 1)
,(14, 4, 25, 1)
,(15, 4, 46, 4)
,(16, 4, 60, 4)
,(17, 4, 72, 4)
,(18, 4, 84, 4);
INSERT INTO @Teams ([id], [Name])
VALUES (1, 'Chelsea')
,(2, 'Arsenal')
,(3, 'Tottenham')
,(4, 'Real Madrid');
INSERT INTO @Managers ([Id], [Name], [TeamID])
VALUES (1, 'Conte', 1)
,(2, 'Wenger', 2)
,(3, 'Pochettino', 3)
,(4, 'Zidane', 4);
WITH DataSource AS
(
SELECT m.[id]
,m.[HomeTeamID]
,m.[AwayTeamID]
,ROW_NUMBER() OVER (PARTITION BY m.[id] ORDER BY g.[minute]) AS [EventID]
,IIF
(
SUM(IIF(m.[HomeTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) - 1
=
SUM(IIF(m.[AwayTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
OR
SUM(IIF(m.[HomeTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
=
SUM(IIF(m.[AwayTeamID] = g.[teamID], 1, 0)) OVER (PARTITION BY m.[id] ORDER BY g.[minute] ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) -1
,IIF(m.[HomeTeamID] = g.[teamID], 'H', 'A') -- (H)ome come back, (A)way come ba
,'N' -- no come back
) AS [ComeBack]
FROM @matches m
INNER JOIN @Goals g
ON m.[id] = g.[MatchID]
)
SELECT T.[Name]
FROM DataSource DS
INNER JOIN @Teams T
ON IIF([ComeBack] = 'H', [HomeTeamID], [AwayTeamID]) = T.[id]
WHERE DS.[EventID] <> 1
AND DS.[ComeBack] <> 'N';
以上将为我们提供:
Chelsea
Chelsea
Chelsea
Tottenham
Real Madrid
Real Madrid
注意,我又添加了一场比赛来证明这一点。
这里"Comeback"表示球队先失球,但球队赢了这场比赛。
我使用 2 个通用子查询,1) winners
,其中包含每个未以平局结束的游戏的 MatchID
和 TeamID
。和 2) first_goals
,其中包含那些 TeamID
,它们在比赛中打进了第一个进球。
因此,使用以下方式连接这些子查询:
on winners.MatchID = first_goals.MatchID and winners.TeamID <> first_goals.TeamID
为我们提供了那些球队获胜但未取得第一个进球的比赛(即 "Comeback")。
最后我们对 Teams
和 Managers
表使用简单连接:
with Goals(id , MatchID , Minute ,TeamID) as (
select 1 , 1 , 3 , 2 union all
select 2 , 1 , 5 , 1 union all
select 3 , 1 , 15 , 1 union all
select 4 , 2 , 43 , 3 union all
select 5 , 2 , 75 , 1 union all
select 6 , 2 , 85 , 1 union all
select 7 , 3 , 11 , 1 union all
select 8 , 3 , 13 , 3 union all
select 9 , 3 , 77 , 3
),
Teams (id, Name) as(
select 1 ,'Chelsea' union all
select 2 ,'Arsenal' union all
select 3 ,'Tottenham'
),
Managers(id, Name, TeamID) as (
select 1 ,'Conte', 1 union all
select 2 ,'Wenger', 2 union all
select 3 ,'Pochettino', 3
)
select winners.TeamID, winners.MatchID, Teams.Name, Managers.Name from (
select t1.* from
(
select TeamID, MatchID, count(*) as goal_scored from Goals
group by TeamID, MatchID
)t1
inner join
(
select MatchID, max(goal_scored) as winner_goals_cnt from (
select TeamID, MatchID, count(*) as goal_scored from Goals
group by TeamID, MatchID
)t
group by MatchID
having min(goal_scored) <> max(goal_scored)
)t2
on t1.MatchID = t2.MatchID and t1.goal_scored = t2.winner_goals_cnt
) winners
inner join
(
select * from (
select Goals.*, row_number() over(partition by MatchID order by Minute, id) rn from Goals
) f
where rn = 1
) first_goals
on winners.MatchID = first_goals.MatchID and winners.TeamID <> first_goals.TeamID
inner join Teams
on winners.TeamID = Teams.id
inner join Managers
on winners.TeamID = Managers.TeamID