我正在尝试创建一个循环风格的足球锦标赛,每支球队每周比赛一次(也只有一次),联盟包含12支球队。
使用下面的代码作为示例,您应该能够看到我有12个团队。我已经使用CTE来生成macth灯具,这样每个队伍都可以在主场和对方之间互相比赛一次(这会产生132场比赛)。
由于共有12支球队共132场比赛,因此每周应该有6场比赛,为期22周。
我如何生成每个夹具发生的周数?
DECLARE @Temp TABLE(
TeamName VARCHAR(100),
MatchWeek INT
)
INSERT INTO @Temp(TeamName) VALUES
('Team1'),
('Team2'),
('Team3'),
('Team4'),
('Team5'),
('Team6'),
('Team7'),
('Team8'),
('Team9'),
('Team10'),
('Team11'),
('Team12');
SELECT t1.Teamname, t2.Teamname
FROM @Temp t1, @Temp t2
WHERE t1.TeamName <> t2.TeamName
答案 0 :(得分:10)
这样做。 Demo
如the Wikipedia entry the algorithm was taken from中所述,它使用以下位置。
最后一个团队(词典排序)将固定在绿色位置。所有其他球队将围绕1-11位置轮换。使用每对的顶部和底部成员作为主队或客场球队之间的固定装置之间交替,以避免为队伍提供长序列。
如果出现奇数队,一支球队每周都没有比赛。下面通过在这种情况下创建一个虚拟空行然后使用相同的算法来处理这个问题。
WITH Teams
AS (SELECT TeamName,
TeamNum = ROW_NUMBER() OVER (ORDER BY TeamName),
TeamCount = COUNT(*) OVER()
FROM @Temp
/*Purpose of below is to add an extra dummy team if odd number
of teams. This null team name will be matched up against competitors
having no game that week */
GROUP BY TeamName WITH ROLLUP
HAVING GROUPING(TeamName) = 0
OR COUNT(*) %2 = 1),
Weeks
AS ( /*We need numbers 1- 11 for a 12 team league etc.
Can use the row numbers calculated above for this*/
SELECT TeamNum AS Week
FROM Teams
WHERE TeamNum < TeamCount),
Positioned
AS (SELECT TeamName,
TeamNum,
Week,
position,
TeamCount
FROM Teams
CROSS JOIN Weeks
/*Uses scheduling algorithm from Wikipedia with the last team in fixed position
and all other teams rotating around (between positions 1 and 11 in 12 team example)*/
CROSS APPLY (SELECT CASE
WHEN TeamNum = TeamCount THEN TeamCount
ELSE 1 + ( ( TeamNum + Week - 1 ) % ( TeamCount - 1 ) )
END) CA(position))
SELECT V.*
FROM Positioned P1
JOIN Positioned P2
ON P1.Week = P2.Week
/*Sum of positions should add up to TeamCount + 1*/
AND P1.position = 1 + P2.TeamCount - P2.position
/*Choose Home and Away from alternating Top and Bottom of pair to
avoid long runs of either for a team*/
AND (P2.Week %2 = 0 AND P1.position < P2.position
OR P2.Week %2 = 1 AND P1.position > P2.position)
/*For second half of the season just reversing the "Home" and "Away" teams */
CROSS APPLY ( VALUES(P1.TeamName, P2.TeamName, P1.Week),
(P2.TeamName, P1.TeamName, P1.Week + P1.TeamCount - 1) ) V(HomeTeam, AwayTeam, Week)
/*Exclude any dummy matches if odd number of teams*/
WHERE V.AwayTeam IS NOT NULL
AND V.HomeTeam IS NOT NULL
ORDER BY V.Week
或者,通过使用此方法交换上述查询的最后一部分,可以通过一些聚合避免Positioned
的自联接。 demo
Positioned
AS (SELECT TeamName,
TeamNum,
Week,
position,
TeamCount,
/*Sum of opposing positions should add up to TeamCount + 1 so can calculate slot for grouping*/
Slot = CASE WHEN position <= TeamCount / 2 THEN position ELSE TeamCount + 1 - position END
FROM Teams
CROSS JOIN Weeks
/*Uses scheduling algorithm from Wikipedia with the last team in fixed position
and all other teams rotating around (between positions 1 and 11 in 12 team example)*/
CROSS APPLY (SELECT CASE
WHEN TeamNum = TeamCount
THEN TeamCount
ELSE 1 + ( ( TeamNum + Week ) % ( TeamCount - 1 ) )
END) CA(position)),
Matches
AS (SELECT Week,
Slot,
TeamCount,
TopTeam = MAX(CASE WHEN position = slot THEN TeamName END),
BottomTeam = MAX(CASE WHEN position <> slot THEN TeamName END)
FROM Positioned
GROUP BY Week,
Slot,
TeamCount)
SELECT CA.*
FROM Matches
CROSS APPLY (
/*Choose Home and Away from alternating Top and Bottom of pair to
avoid long runs of either for a team*/
/*First two rows are for alternate weeks in the 1st half of the season */
SELECT TopTeam, BottomTeam, Week
WHERE Week %2 = 0
UNION ALL
SELECT BottomTeam, TopTeam, Week
WHERE Week %2 > 0
UNION ALL
/*For second half of the season just reversing the "Home" and "Away" teams */
SELECT BottomTeam, TopTeam, Week + TeamCount - 1
WHERE Week %2 = 0
UNION ALL
SELECT TopTeam, BottomTeam, Week + TeamCount - 1
WHERE Week %2 > 0) CA(HomeTeam, AwayTeam, Week)
/*Exclude any dummy matches if odd number of teams*/
WHERE CA.AwayTeam IS NOT NULL
AND CA.HomeTeam IS NOT NULL
ORDER BY CA.Week;
答案 1 :(得分:3)
所以这里的理论是:https://nrich.maths.org/1443
要在SQL中实现,首先我们需要一个团队列表
DECLARE @teams TABLE(
TeamId int identity(0,1),
TeamName VARCHAR(100)
)
INSERT @teams(TeamName) VALUES
('Team01'),
('Team02'),
('Team03'),
('Team04'),
('Team05'),
('Team06'),
('Team07'),
('Team08'),
('Team09'),
('Team10'),
('Team11'),
('Team12');
现在我们创建循环夹具套装。我确定可以使用几何对象并旋转它们,但是......
declare @roundRobin table (fixtureId int, week int, homeTeam int, awayTeam int)
insert @roundRobin
select 1, 1, 0, 1
union select 2, 1, 2, 3
union select 3, 1, 4, 5
union select 4, 1, 6, 7
union select 5, 1, 8, 9
union select 6, 1, 10, 11
declare @week int = 2
while @week <= 11
begin
insert @roundRobin
select 1, @week, 0, awayTeam from @roundRobin where week = @week - 1 and fixtureId=2
union all
select 2, @week,(select awayTeam from @roundRobin where week = @week - 1 and fixtureId=1), (select awayTeam from @roundRobin where week = @week - 1 and fixtureId=3)
union all
select 3, @week,(select homeTeam from @roundRobin where week = @week - 1 and fixtureId=2), (select awayTeam from @roundRobin where week = @week - 1 and fixtureId=4)
union all
select 4, @week,(select homeTeam from @roundRobin where week = @week - 1 and fixtureId=3), (select awayTeam from @roundRobin where week = @week - 1 and fixtureId=5)
union all
select 5, @week,(select homeTeam from @roundRobin where week = @week - 1 and fixtureId=4), (select awayTeam from @roundRobin where week = @week - 1 and fixtureId=6)
union all
select 6,@week,(select homeTeam from @roundRobin where week = @week - 1 and fixtureId=5), (select homeTeam from @roundRobin where week = @week - 1 and fixtureId=6)
select @week = @week + 1
end
现在创建一组这样的赛程,主场和客队都会逆转。
insert @roundRobin
select fixtureId, week+11, awayTeam, homeTeam from @roundRobin
以随机顺序创建一个周列表以停止回家/远程灯具的运行
declare @weeks table (Week int, WeekOrder int)
insert @weeks
select number, row_number() over (order by randomorder)
from
( select number, newid() randomorder from master..spt_values where type='p' and number between 1 and 22 ) v
order by number
现在,每个星期的赛程。多田!
select
weekorder,
ht.TeamName homeTeam,
at.TeamName awayTeam
from @weeks w
inner join @roundRobin rr on w.Week = rr.week
inner join @teams ht on rr.homeTeam = ht.TeamId
inner join @teams at on rr.awayTeam = at.TeamId
order by weekorder, hometeam
我现在对高级联赛夹具电脑有了新的尊重。