Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment coder un certain algorithme mathématique

Une autre solution Oracle.

Configuration :

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 );

Insérer - Appareils :

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;

Sortie :

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 

(Remarque :FixtureDate est NULL car il n'est pas clair comment vous voulez que cela soit généré, mais vous devriez pouvoir prendre le numéro de semaine et l'utiliser comme décalage depuis le début de la saison pour générer des dates)