简体   繁体   English

在 PL/SQL 中实现双循环算法

[英]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_SCHEDULEMATCH_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脚本并运行它。

SQL Fiddle SQL小提琴

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

Results :结果

| 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM