[英]Implementing Double Round Robin Algorithm in PL/SQL
I'm new to SQL
and I'm trying to make a table which stores the schedule of a football league.我是SQL
新手,我正在尝试制作一个表来存储足球联赛的时间表。 The table contains 4 columns ( matchID, home_team, away_team, match_date
).该表包含 4 列( matchID, home_team, away_team, match_date
)。 I have 8 different teams and each team should play against each of the other teams exactly twice.我有 8 支不同的球队,每支球队都应该与其他球队对战两次。 The tournament will last for 14 weeks(4 games per week).比赛将持续 14 周(每周 4 场)。 I searched and found out that the double round robin algorithm
does the same thing but I'm not sure how to write it in PL/SQL and generate a table.我搜索并发现double round robin algorithm
做了同样的事情,但我不确定如何在 PL/SQL 中编写它并生成一个表。 Please help me.请帮帮我。
You can generate records for your Table using this query.您可以使用此查询为您的表生成记录。 Note here that I have not enforced any constraints
which is up to you and you should .请注意,我没有强制执行任何由您决定的constraints
,您应该这样做。 You can write simple CREATE TABLE (
syntax with all datatype and constraints and use this query to insert
records.您可以编写简单的CREATE TABLE (
包含所有数据类型和约束的语法,并使用此查询insert
记录。
match_groups generates the match combinations match_groups生成匹配组合
All_matches repeats the matches by swapping home team and away team. All_matches通过交换主队和客队来重复比赛。
CREATE TABLE MATCH_SCHEDULE AS WITH TEAMS (name) AS
(SELECT 'TEAM1'
FROM DUAL
UNION ALL SELECT 'TEAM2'
FROM DUAL
UNION ALL SELECT 'TEAM3'
FROM DUAL
UNION ALL SELECT 'TEAM4'
FROM DUAL
UNION ALL SELECT 'TEAM5'
FROM DUAL
UNION ALL SELECT 'TEAM6'
FROM DUAL
UNION ALL SELECT 'TEAM7'
FROM DUAL
UNION ALL SELECT 'TEAM8'
FROM DUAL),
match_groups AS
(SELECT t1.name home_team,
t2.name away_team
FROM
(SELECT rownum RNUM,
NAME
FROM TEAMS) t1
JOIN
(SELECT rownum RNUM,
NAME
FROM TEAMS) t2 ON t1.RNUM < t2.RNUM),
All_matches AS
(SELECT home_team,
away_team
FROM match_groups
UNION ALL SELECT away_team home_team,
home_team away_team
FROM match_groups)
SELECT ROWNUM matchID,
home_team,
away_team,
SYSDATE + ROWNUM match_date
FROM All_matches;
This would create a table with following data.这将创建一个包含以下数据的表。
TABLE MATCH_SCHEDULE表MATCH_SCHEDULE
MATCHID HOME_TEAM AWAY_TEAM MATCH_DATE
1 TEAM1 TEAM2 09-OCT-17
2 TEAM1 TEAM3 10-OCT-17
3 TEAM1 TEAM4 11-OCT-17
4 TEAM1 TEAM5 12-OCT-17
5 TEAM1 TEAM6 13-OCT-17
6 TEAM1 TEAM7 14-OCT-17
...
...
54 TEAM7 TEAM6 01-DEC-17
55 TEAM8 TEAM6 02-DEC-17
56 TEAM8 TEAM7 03-DEC-17
Note that MATCHID
has just numbers 1,2,3.... You can also make use of an Oracle sequence
if you like or update it accordingly.请注意MATCHID
只有数字 1,2,3.... 如果您喜欢或相应地更新它,您也可以使用 Oracle sequence
。 Now, since you need to have 4 matches per week, you need to construct an adhoc update
script based on your need with proper dates and run it.现在,由于您每周需要进行 4 场比赛,因此您需要根据您的需要构建一个具有适当日期的临时update
脚本并运行它。
Oracle 11g R2 Schema Setup : Oracle 11g R2 架构设置:
CREATE TABLE matches ( matchID, home_team, away_team, match_date ) AS
WITH rounds ( round, home, away, num_players ) AS (
SELECT 1,
LEVEL,
num_players + 1 - LEVEL,
num_players
FROM ( SELECT 8 AS num_players FROM DUAL )
CONNECT BY LEVEL <= num_players / 2
UNION ALL
SELECT round + 1,
CASE home
WHEN 1 THEN 1
WHEN 2 THEN num_players
ELSE home - 1
END,
CASE away
WHEN 2 THEN num_players
ELSE away - 1
END,
num_players
FROM rounds
WHERE round < num_players - 1
)
SELECT ROWNUM,
t.*
FROM (
SELECT home,
away,
DATE '2017-01-01' + ( round - 1 ) * 7 AS match_date
FROM rounds
UNION ALL
SELECT away,
home,
DATE '2017-01-01' + ( round + num_players - 2 ) * 7
FROM rounds
) t;
Query 1 :查询 1 :
SELECT * FROM matches
| MATCHID | HOME_TEAM | AWAY_TEAM | MATCH_DATE |
|---------|-----------|-----------|----------------------|
| 1 | 1 | 8 | 2017-01-01T00:00:00Z |
| 2 | 2 | 7 | 2017-01-01T00:00:00Z |
| 3 | 3 | 6 | 2017-01-01T00:00:00Z |
| 4 | 4 | 5 | 2017-01-01T00:00:00Z |
| 5 | 1 | 7 | 2017-01-08T00:00:00Z |
| 6 | 8 | 6 | 2017-01-08T00:00:00Z |
| 7 | 2 | 5 | 2017-01-08T00:00:00Z |
| 8 | 3 | 4 | 2017-01-08T00:00:00Z |
| 9 | 1 | 6 | 2017-01-15T00:00:00Z |
| 10 | 7 | 5 | 2017-01-15T00:00:00Z |
| 11 | 8 | 4 | 2017-01-15T00:00:00Z |
| 12 | 2 | 3 | 2017-01-15T00:00:00Z |
| 13 | 1 | 5 | 2017-01-22T00:00:00Z |
| 14 | 6 | 4 | 2017-01-22T00:00:00Z |
| 15 | 7 | 3 | 2017-01-22T00:00:00Z |
| 16 | 8 | 2 | 2017-01-22T00:00:00Z |
| 17 | 1 | 4 | 2017-01-29T00:00:00Z |
| 18 | 5 | 3 | 2017-01-29T00:00:00Z |
| 19 | 6 | 2 | 2017-01-29T00:00:00Z |
| 20 | 7 | 8 | 2017-01-29T00:00:00Z |
| 21 | 1 | 3 | 2017-02-05T00:00:00Z |
| 22 | 4 | 2 | 2017-02-05T00:00:00Z |
| 23 | 5 | 8 | 2017-02-05T00:00:00Z |
| 24 | 6 | 7 | 2017-02-05T00:00:00Z |
| 25 | 1 | 2 | 2017-02-12T00:00:00Z |
| 26 | 3 | 8 | 2017-02-12T00:00:00Z |
| 27 | 4 | 7 | 2017-02-12T00:00:00Z |
| 28 | 5 | 6 | 2017-02-12T00:00:00Z |
| 29 | 8 | 1 | 2017-02-19T00:00:00Z |
| 30 | 7 | 2 | 2017-02-19T00:00:00Z |
| 31 | 6 | 3 | 2017-02-19T00:00:00Z |
| 32 | 5 | 4 | 2017-02-19T00:00:00Z |
| 33 | 7 | 1 | 2017-02-26T00:00:00Z |
| 34 | 6 | 8 | 2017-02-26T00:00:00Z |
| 35 | 5 | 2 | 2017-02-26T00:00:00Z |
| 36 | 4 | 3 | 2017-02-26T00:00:00Z |
| 37 | 6 | 1 | 2017-03-05T00:00:00Z |
| 38 | 5 | 7 | 2017-03-05T00:00:00Z |
| 39 | 4 | 8 | 2017-03-05T00:00:00Z |
| 40 | 3 | 2 | 2017-03-05T00:00:00Z |
| 41 | 5 | 1 | 2017-03-12T00:00:00Z |
| 42 | 4 | 6 | 2017-03-12T00:00:00Z |
| 43 | 3 | 7 | 2017-03-12T00:00:00Z |
| 44 | 2 | 8 | 2017-03-12T00:00:00Z |
| 45 | 4 | 1 | 2017-03-19T00:00:00Z |
| 46 | 3 | 5 | 2017-03-19T00:00:00Z |
| 47 | 2 | 6 | 2017-03-19T00:00:00Z |
| 48 | 8 | 7 | 2017-03-19T00:00:00Z |
| 49 | 3 | 1 | 2017-03-26T00:00:00Z |
| 50 | 2 | 4 | 2017-03-26T00:00:00Z |
| 51 | 8 | 5 | 2017-03-26T00:00:00Z |
| 52 | 7 | 6 | 2017-03-26T00:00:00Z |
| 53 | 2 | 1 | 2017-04-02T00:00:00Z |
| 54 | 8 | 3 | 2017-04-02T00:00:00Z |
| 55 | 7 | 4 | 2017-04-02T00:00:00Z |
| 56 | 6 | 5 | 2017-04-02T00:00:00Z |
Try this procedure.试试这个程序。 The logic is based on round robin逻辑基于循环
Note that I used: week instead of date.请注意,我使用了:week 而不是 date。 Scheduling the matches for a specific date requires other information on how many per day, can you have a team playing more than once per week, etc.安排特定日期的比赛需要其他信息,例如每天有多少场比赛,您是否可以让一支球队每周比赛不止一次,等等。
The input to the procedure is a comma separated team list.该过程的输入是一个逗号分隔的团队列表。 If you input odd number, a "DUMMY" is created for round robin to work.如果您输入奇数,则会创建一个“DUMMY”以供轮循机制工作。 This does not insert into a table but prompt you the schedule.这不会插入到表中,而是提示您时间表。 You can replace the DBMS_OUTPUT
statements with insert statements您可以用插入语句替换DBMS_OUTPUT
语句
create or replace
procedure test_schedule(p_teams in varchar2)
is
type t_teams is table of varchar2(15);
cursor c_teams is
select trim(regexp_substr(p_teams,'[^,]+', 1, level)) team
from dual
connect by regexp_substr(p_teams, '[^,]+', 1, level) is not null;
v_teams t_teams := t_teams();
v_team_shift varchar2(60);
v_weeks number;
v_count number:=0;
v_date date;
begin
for r_teams in c_teams loop
v_count := v_count + 1;
v_teams.extend();
v_teams(v_count) := r_teams.team;
end loop;
if mod(v_count, 2) != 0 then
v_count := v_count + 1;
v_teams.extend();
v_teams(v_count) := 'DUMMAY';
end if;
for i in 1..v_count loop
dbms_output.put_line(v_teams(i));
end loop;
v_weeks := v_count - 1;
dbms_output.put_line('Weeks: '|| v_weeks||' Count: '||v_count);
for week in 1..v_weeks loop
for i in 1..v_count/2 loop
dbms_output.put_line(week||': '||v_teams(i)||' X '||v_teams(v_count-i+1));
dbms_output.put_line(week+v_weeks||': '||v_teams(v_count-i+1)||' X '||v_teams(i));
end loop;
-- shift teams
v_team_shift := v_teams(v_count);
for i in 1..v_count-2 loop
v_teams(v_count-i+1) := v_teams(v_count-i);
end loop;
v_teams(2) := v_team_shift;
end loop;
end;
/
To test, I used:为了测试,我使用了:
begin test_schedule('TEAM A, TEAM B, TEAM C, TEAM D, TEAM E'); end;
/
The output:输出:
Week Home Away
1: TEAM A X DUMMAY
6: DUMMAY X TEAM A
1: TEAM B X TEAM E
6: TEAM E X TEAM B
1: TEAM C X TEAM D
6: TEAM D X TEAM C
2: TEAM A X TEAM E
7: TEAM E X TEAM A
2: DUMMAY X TEAM D
7: TEAM D X DUMMAY
2: TEAM B X TEAM C
7: TEAM C X TEAM B
3: TEAM A X TEAM D
8: TEAM D X TEAM A
3: TEAM E X TEAM C
8: TEAM C X TEAM E
3: DUMMAY X TEAM B
8: TEAM B X DUMMAY
4: TEAM A X TEAM C
9: TEAM C X TEAM A
4: TEAM D X TEAM B
9: TEAM B X TEAM D
4: TEAM E X DUMMAY
9: DUMMAY X TEAM E
5: TEAM A X TEAM B
10: TEAM B X TEAM A
5: TEAM C X DUMMAY
10: DUMMAY X TEAM C
5: TEAM D X TEAM E
10: TEAM E X TEAM D
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.