【问题标题】:Implementing Double Round Robin Algorithm in PL/SQL在 PL/SQL 中实现双循环算法
【发布时间】:2017-10-08 09:50:27
【问题描述】:

我是SQL 的新手,我正在尝试制作一个存储足球联赛时间表的表格。该表包含 4 列 (matchID, home_team, away_team, match_date)。我有 8 支不同的球队,每支球队都应该与其他球队交手两次。比赛将持续 14 周(每周 4 场比赛)。我搜索并发现double round robin algorithm 做了同样的事情,但我不确定如何用 PL/SQL 编写它并生成一个表。请帮帮我。

【问题讨论】:

  • 这个问题看起来有很多遗漏。例如,是否有关于一支球队在特定时间范围内比赛的频率的规定,是否允许主客场比赛连续进行,所有比赛的实际时间范围是什么(以及我确定的许多其他比赛) )

标签: sql oracle algorithm plsql


【解决方案1】:

SQL Fiddle

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;

查询 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 |

【讨论】:

    【解决方案2】:

    您可以使用此查询为您的表生成记录。请注意,我没有强制执行任何constraints,这取决于您并且您应该。您可以使用所有数据类型和约束编写简单的CREATE TABLE ( 语法,并将此查询用于insert 记录。

    ma​​tch_groups 生成匹配组合

    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;
    

    这将创建一个包含以下数据的表。

    表格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
    

    请注意,MATCHID 只有数字 1、2、3...。如果您愿意,也可以使用 Oracle sequence 或相应地更新它。现在,由于您需要每周进行 4 场比赛,因此您需要根据您的需要构建一个具有适当日期的临时 update 脚本并运行它。

    【讨论】:

    • 谢谢。表已成功创建。但是我有一个问题,根据循环赛算法,一个球队不能参加第二场比赛,直到所有其他球队都打完他们的第一场比赛。这就是为什么我希望每周进行 4 场比赛,以便所有 8 支球队都能完成他们的第一场比赛。看看这个tournamentscheduler.net/schedule/NDg2NDg0MzUzNg
    • 如果是一次性活动,您可以从 excel 生成更新脚本以将其更新为正确的日期。例如:update table SET matchdate = &lt;firstdate&gt; where home_team = TEAM3 AND away_team = TEAM1 ,update table SET matchdate = &lt;seconddate&gt; where home_team = TEAM5 AND away_team = TEAM7 .. 等等。
    • 是的,这很简单,但很耗时。有没有办法创建一个程序?而且我想如果一周内所有 4 场比赛的 match_date 保持相同以便所有 4 场比赛在同一天举行会更容易。因此,每支球队都会在一周后进行一场比赛。
    【解决方案3】:

    试试这个过程。逻辑是基于循环的

    请注意,我使用的是:周而不是日期。安排特定日期的比赛需要其他信息,例如每天有多少场比赛,您是否可以让一支球队每周比赛超过一次,等等。

    该过程的输入是一个逗号分隔的团队列表。如果您输入奇数,则会创建一个“DUMMY”,以便循环工作。这不会插入到表中,但会提示您计划。您可以将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;
        /
    

    为了测试,我使用了:

    begin test_schedule('TEAM A, TEAM B, TEAM C, TEAM D, TEAM E'); end;
    /
    

    输出:

        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
    

    【讨论】:

      猜你喜欢
      • 2013-12-22
      • 2013-09-13
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 1970-01-01
      • 2013-07-21
      • 2023-04-01
      • 2012-03-27
      相关资源
      最近更新 更多