2016-06-09 13 views
9

Tôi đã được đưa ra thuật toán này để giúp tôi tạo một danh sách lịch thi đấu trong SQL, nhưng áp dụng nó như là mã SQL, tôi không có ý tưởng làm thế nào để làm. Có cách ai đó có thể hướng dẫn tôi về cách áp dụng nó với mã không?Làm thế nào để mã hóa một thuật toán toán học nhất định

Dưới đây là sơ đồ bảng của tôi và dưới đó là các thuật toán:

League:

[LeagueID] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
[LeagueName] VARCHAR(30) UNIQUE 

Đội bóng:

[TeamID] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
[TeamAbbreviation] CHAR(3) UNIQUE, 
[TeamName] VARCHAR(50) UNIQUE, 
[LeagueID] TINYINT CONSTRAINT FK_Team_League FOREIGN KEY REFERENCES League(LeagueID) 

Fixture:

[FixtureID] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
[WeekNumber] INT NOT NULL, 
[FixtureDate] DATE NULL, 
[HomeTeamID] TINYINT NULL, 
[AwayTeamID] TINYINT NULL, 
[LeagueID] TINYINT CONSTRAINT FK_Fixture_League FOREIGN KEY REFERENCES League(LeagueID) 

Thuật toán:

Cho phép chúng tôi dịch các thuật toán, được gọi là round robin scheduling, trong điều khoản của một danh sách có thứ l của đội N (tương ứng với N-1 đa giác đỉnh + trung tâm đa giác):

  • l định nghĩa cố định bằng cách chơi nhóm đầu tiên từ danh sách so với người cuối cùng, nhóm thứ hai so với đội đầu tiên trước, v.v.
    Tức là, đối với 0 ≤ x < N, bạn chơi đội l[x] với đội l[N-1-x].

  • Để tạo bộ đồ đạc tiếp theo, bạn xoay các thành phần đầu tiên của danh sách N-1.
    Đó là l = l[1] + l[2] + ... + l[N-2] + l[0] + l[N-1]

  • Khi bạn đã thực hiện đầy đủ các N-1 quay, làm điều đó một lần nữa nhưng trao đổi nhà và sân khách đội: chơi đội l[N-1-x] vs đội l[x] thay vì ngược lại.

Nếu bạn bắt đầu với danh sách số lượng đặt hàng 0..N-1 sau đó tại vòng i danh sách là:
l = [(i + 0) % (N-1)] + [(i + 1) % (N-1)] + ... + [(i + N-2) % (N-1)] + [N-1]

Đó là, đồ đạc đang ở vòng i:

  • i vs N-1
  • Đối 0 < x < (N-1)/2, (x + i) % (N-1) vs (N-1 - x + i) % (N-1)

Bây giờ có một trick, như này chỉ hoạt động cho số chẵn. Nếu không, đội cuối cùng luôn chơi (đối đầu với đội i ở vòng i) trong khi mỗi vòng tự nhiên có một đội không thể chơi. Điều đó có nghĩa là đội 4 chơi một trận đấu nhiều hơn các đội khác.

Để giải quyết việc này, chúng tôi thêm một đội hình nộm, như vậy cho 5 đội chúng tôi có N = 6, và ở vòng i:

  • i vs 5 (đội dummy)
  • (i + 1) % 4 vs (4 + i) % 4
  • (i + 2) % 4 vs (3 + i) % 4

Bây giờ bạn biết điều này, bạn có thể tạo ra một hàm sẽ cung cấp cho bạn đồ đạc dựa trên số vòng. Nó nên đầu ra như sau:

vòng 0: 0 nghỉ, 1 vs 4, 2 vs 3
vòng 1: 1 nghỉ, 2 vs 0, 3 vs 4
vòng 2: 2 nghỉ, 3 vs 1, 4 vs 0
vòng 3: 3 nghỉ, 4 vs 2, 0 vs 1
vòng 4: 4 nghỉ, 0 vs 3, 1 vs 2


Lưu ý rằng thay vì i trong các công thức x + iN-1 - x + i bạn có thể sử dụng bất kỳ số nào nhiều m * i (vì vậy x + m * iN-1 - x + m * i) miễn là mN-1relatively prime. Ở đây N - 1 = 5 là số nguyên tố, vì vậy bạn có thể sử dụng bất kỳ số m nào bạn muốn.

UPDATE:

Theo yêu cầu dưới đây là ngươi kiểm tra dữ liệu cho đầu bảng League và thứ hai bảng đội (phù hợp với các cột schema bảng theo thứ tự)

League:

1, 'English Premiership' 
2, 'English Division 1' 

Đội:

1, 'BCN', 'FC Barcelona', 1 
2, 'MAD', 'Real Madrid', 1 
3, 'ATH', 'Athletico Madrid', 1 
4, 'ESP', 'Espanyol', 1 
5, 'MAN', 'Manchester United', 2 
6, 'BOL', 'Bolton', 2 
7, 'CHE', 'Chelsea', 2 
8, 'ARS', 'Arsenal', 2 

Các đội chơi mỗi gia đình khác và đi và chỉ có thể thi đấu với các đội người trong cùng một giải đấu (do đó LeagueIDs khác nhau)

Các trận đấu sẽ như thế này cho mỗi vòng:

League 1: 

Round 1- 01/05/2016: 
1v4, 2v3 

Round 2- 08/05/2016: 
1v2, 3v4 

Round 3- 15/05/2016: 
3v1, 4v2 

Round 4- 22/05/2016: 
4v1, 3v2 

Round 5- 29/05/2016: 
2v1, 4v3 

Round 6- 05/06/2016: 
1v3, 2v4 


League 2: 

Round 1- 01/05/2016: 
5v8, 6v7 

Round 2- 08/05/2016: 
5v6, 7v8 

Round 3- 15/05/2016: 
3v1, 4v2 

Round 4- 22/05/2016: 
8v5, 7v6 

Round 5- 29/05/2016: 
6v5, 8v7 

Round 6- 05/06/2016: 
5v7, 6v8 
  • giải số là
  • số Round 'LeagueID' là 'WeekNumber'
  • ngày là 'ngày thi đấu'
  • số đội nhà là 'HomeTeamID'
  • Số đội khách là 'AwayTeamID'

Tất cả điều này sẽ được đưa vào bảng 'Lịch thi đấu'.

+4

Bây giờ, đó là cách câu hỏi nên được hỏi. –

+0

chỉ liên kết với bạn câu hỏi liên quan trước đó: http://stackoverflow.com/questions/37610060/creating-a-fixture-list-logic – Tanner

+0

@Tanner Cool, vâng vấn đề với cách tiếp cận trước đó là mặc dù nó hiển thị chính xác các nhóm , nó gặp sự cố khi hiển thị số tuần chính xác cho mỗi vòng kết quả phù hợp. Bằng cách này, sử dụng thuật toán sẽ giúp giải quyết vấn đề tuần nhưng nó là một tuyến hoàn toàn mới và nhiều hơn nữa toán học –

Trả lời

1

Một giải pháp khác của Oracle.

Cài đặt:

CREATE TABLE League (
    LeagueID INT PRIMARY KEY, 
    LeagueName VARCHAR(30) UNIQUE 
); 

CREATE TABLE Team (
    TeamID   INT PRIMARY KEY, 
    TeamAbbreviation CHAR(3) UNIQUE, 
    TeamName   VARCHAR(50) UNIQUE, 
    LeagueID   INT CONSTRAINT FK_Team_League REFERENCES League(LeagueID) 
); 

CREATE TABLE Fixture (
    FixtureID INT PRIMARY KEY, 
    WeekNumber INT NOT NULL, 
    FixtureDate DATE NULL, 
    HomeTeamID INT NULL, 
    AwayTeamID INT NULL, 
    LeagueID INT CONSTRAINT FK_Fixture_League REFERENCES League(LeagueID) 
); 

INSERT INTO League VALUES (1, 'League 1'); 
INSERT INTO League VALUES (2, 'League 2'); 

INSERT INTO Team VALUES (1, 'AAA', 'Team A', 1); 
INSERT INTO Team VALUES (2, 'BBB', 'Team B', 1); 
INSERT INTO Team VALUES (3, 'CCC', 'Team C', 1); 
INSERT INTO Team VALUES (4, 'DDD', 'Team D', 1); 
INSERT INTO Team VALUES (5, 'EEE', 'Team E', 2); 
INSERT INTO Team VALUES (6, 'FFF', 'Team F', 2); 
INSERT INTO Team VALUES (7, 'GGG', 'Team G', 2); 
INSERT INTO Team VALUES (8, 'HHH', 'Team H', 2); 
INSERT INTO Team VALUES (9, 'III', 'Team I', 2); 

Insert - Lịch thi đấu:

INSERT INTO Fixture 
WITH league_teams (id, leagueid, idx, is_fake, num_teams, num_fake) AS (
    -- Generate a unique-per-league index for each team that is between 0 
    -- and the (number of teams - 1) and calculate the number of teams 
    -- and if this is an odd number then generate a fake team as well. 
    SELECT TeamID, 
     LeagueID, 
     ROW_NUMBER() OVER (PARTITION BY LeagueID ORDER BY TeamID) - 1, 
     0, 
     COUNT(1) OVER (PARTITION BY LeagueID), 
     MOD(COUNT(1) OVER (PARTITION BY LeagueID), 2) 
    FROM Team 
    UNION ALL 
    SELECT NULL, 
     LeagueID, 
     COUNT(1), 
     1, 
     COUNT(1), 
     1 
    FROM Team 
    GROUP BY LeagueID 
    HAVING MOD(COUNT(1), 2) > 0 
), 
cte (home_idx, away_idx, week_number, leagueID, num_teams, num_fake) AS (
    -- Start by calculating the round 1 games 
    SELECT idx, 
     num_teams + num_fake - 1 - idx, 
     1, 
     LeagueID, 
     num_teams, 
     num_fake 
    FROM league_teams 
    WHERE 2 * idx < num_teams 
UNION ALL 
    -- Then generate the successive rounds with the two cases when the 
    -- away team has the maximum index or otherwise. 
    SELECT CASE away_idx 
      WHEN num_teams + num_fake - 1 
      THEN home_idx + 1 
      ELSE MOD(home_idx + 1, num_teams + num_fake -1) 
      END, 
     CASE away_idx 
      WHEN num_teams + num_fake - 1 
      THEN away_idx 
      ELSE MOD(away_idx + 1, num_teams + num_fake - 1) 
      END, 
     week_number + 1, 
     LeagueID, 
     num_teams, 
     num_fake 
    FROM cte 
    WHERE week_number < num_teams + num_fake - 1 
) 
-- Finally join the cte results back to the League_Teams table to convert 
-- the indexes used in calculation back to the actual team ids. 
SELECT rn, 
     week_number, 
     NULL, 
     h.id, 
     a.id, 
     c.leagueid 
FROM (
     -- This step isn't necessary but it keeps the results in a nice order. 
     SELECT ROWNUM AS rn, 
       t.* 
     FROM (
      -- Duplicate the results swapping home and away. 
      SELECT week_number, 
        home_idx, 
        away_idx, 
        LeagueId 
      FROM cte 
      UNION ALL 
      SELECT week_number + num_teams + num_fake - 1, 
        away_idx, 
        home_idx, 
        LeagueId 
      FROM cte 
     ) t 
     ) c 
     INNER JOIN League_Teams h 
     ON (c.home_idx = h.idx AND c.leagueId = h.leagueID) 
     INNER JOIN League_Teams a 
     ON (c.away_idx = a.idx AND c.leagueId = a.leagueID) 
ORDER BY rn; 

Output:

SELECT * FROM fixture; 

FIXTUREID WEEKNUMBER FIXTUREDATE   HOMETEAMID AWAYTEAMID LEAGUEID 
---------- ---------- ------------------- ---------- ---------- ---------- 
     1   1        1   4   1 
     2   1        2   3   1 
     3   1        5      2 
     4   1        6   9   2 
     5   1        7   8   2 
     6   2        2   4   1 
     7   2        3   1   1 
     8   2        6      2 
     9   2        7   5   2 
     10   2        8   9   2 
     11   3        3   4   1 
     12   3        1   2   1 
     13   3        7      2 
     14   3        8   6   2 
     15   3        9   5   2 
     16   4        8      2 
     17   4        9   7   2 
     18   4        5   6   2 
     19   5        9      2 
     20   5        5   8   2 
     21   5        6   7   2 
     22   4        4   1   1 
     23   4        3   2   1 
     24   6           5   2 
     25   6        9   6   2 
     26   6        8   7   2 
     27   5        4   2   1 
     28   5        1   3   1 
     29   7           6   2 
     30   7        5   7   2 
     31   7        9   8   2 
     32   6        4   3   1 
     33   6        2   1   1 
     34   8           7   2 
     35   8        6   8   2 
     36   8        5   9   2 
     37   9           8   2 
     38   9        7   9   2 
     39   9        6   5   2 
     40   10           9   2 
     41   10        8   5   2 
     42   10        7   6   2 

(Lưu ý: FixtureDateNULL vì không rõ bạn muốn tạo ra như thế nào nhưng bạn có thể lấy số tuần và sử dụng số này làm giá trị bù trừ từ đầu mùa để tạo ngày)

+0

Cool MT0, tôi sẽ cho phép điều này khi tôi có cơ hội và cho bạn biết kết quả. Nếu tôi làm cho nó hoạt động thì tôi sẽ đăng giải pháp SQL Server. Cảm ơn bạn –

+0

Hi Mt0, Cho bạn câu trả lời hay nhất khi tôi tin tưởng phiên bản oracle yuor sẽ hoạt động. Đã thử một vài giờ để chuyển đổi bằng SQL Server nhưng chưa thành công. Tôi sẽ gửi một câu hỏi khác để xem nếu có ai có thể chuyển đổi nó thành mã máy chủ sql và liên kết câu hỏi này với câu hỏi đó để giúp những người giao dịch với máy chủ SQL. Cảm ơn bạn rất nhiều :) –

+0

Câu trả lời SQL Server có thể được tìm thấy ở đây: http://stackoverflow.com/questions/37746092/converting-oracle-code-to-sql-server-for-a-fixture-list, Cảm ơn bạn cho tất cả sự giúp đỡ của bạn :) –

1

Sau đây dường như có được những gì bạn muốn - nhưng đây là Oracle SQL (Tôi không có quyền truy cập vào một máy chủ DB DB vào lúc này). Nhưng tôi tin rằng tất cả các bạn cần phải thay đổi là hàm MOD, các nối văn bản, và các tài liệu tham khảo để DUAL để làm cho nó làm việc trên SQL Server:

WITH TEAMS(TEAMID,TEAMNAME) AS (
SELECT 0,'TEAM A' FROM DUAL UNION 
SELECT 1,'TEAM B' FROM DUAL UNION 
SELECT 2,'TEAM C' FROM DUAL UNION 
SELECT 3,'TEAM D' FROM DUAL UNION 
SELECT 4,'TEAM E' FROM DUAL 
), 
TEAMSX(TEAMID,TEAMNAME) AS (
SELECT * FROM TEAMS 
UNION 
SELECT (SELECT COUNT(*) FROM TEAMS) TEAMID,'DUMMY' FROM DUAL WHERE MOD((SELECT COUNT(*) FROM TEAMS),2)<>0), 
TEAM_FIX(ROUND,TEAMID,FIXID) AS (
SELECT 0,TEAMID,TEAMID FROM TEAMSX 
UNION ALL 
SELECT ROUND+1,TEAMID, 
    CASE WHEN TEAMID=(SELECT COUNT(*)-1 FROM TEAMSX) THEN (SELECT COUNT(*)-1 FROM TEAMSX) ELSE 
    MOD(TEAMID+(ROUND+1),(SELECT COUNT(*)-1 FROM TEAMSX)) END FROM TEAM_FIX 
WHERE ROUND < (SELECT COUNT(*)-2 FROM TEAMSX)) 
SELECT ROUND, TXT FROM (
SELECT TEAM1.ROUND,TEAM1.FIXID TM1,TEAM2.FIXID TM2, 
CASE WHEN TX.TEAMNAME='DUMMY' THEN TEAM1.FIXID || ' rests' ELSE TEAM1.FIXID || ' vs ' || TEAM2.FIXID END TXT FROM 
TEAM_FIX TEAM1 
JOIN TEAM_FIX TEAM2 ON (TEAM1.ROUND=TEAM2.ROUND AND TEAM1.TEAMID+TEAM2.TEAMID=(SELECT COUNT(*)-1 FROM TEAMSX) AND TEAM1.TEAMID < TEAM2.TEAMID) 
JOIN TEAMSX TX ON (TEAM2.TEAMID=TX.TEAMID) 
ORDER BY TEAM1.ROUND,TEAM1.TEAMID) 

Đầu tiên VỚI bảng (đội) là chỉ để tạo ra một số mẫu dữ liệu.

Bảng thứ hai (TEAMSX) sẽ tạo nhóm giả nếu chúng tôi có số lượng đội lẻ.

Bảng thứ ba (TEAM_FIX) là CTE đệ quy sử dụng hàm bạn đã tạo để tạo thứ tự danh sách thích hợp cho mỗi vòng.

Sau đó, trong truy vấn chính, chúng tôi tham gia TEAM_FIX chống lại chính nó cho mỗi vòng để tạo ra các trận đấu nhóm.

+0

Cool Mike, tôi sẽ cung cấp cho nó một đi khi tôi có thời gian và cho bạn biết kết quả. Cảm ơn bạn –

Các vấn đề liên quan