Eine weitere Oracle-Lösung.
Einrichtung :
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 );
Einfügen - Geräte :
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;
Ausgabe :
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
(Hinweis:FixtureDate
ist NULL
da es unklar ist, wie Sie dies generieren möchten, aber Sie sollten in der Lage sein, die Wochennummer zu nehmen und diese als Offset vom Beginn der Saison zu verwenden, um Daten zu generieren)