Comment implémenter une entité avec un nombre maximum inconnu d'attributs?

12

Je conçois un programme de simulation de baseball et j'ai rencontré un problème avec la conception du schéma boxscore. Le problème que j'ai, c'est que je veux suivre le nombre de points marqués à chaque manche. La façon dont je le fais dans le programme réel est d'utiliser un tableau dynamique qui grandit pour chaque manche jouée.

Pour ceux qui ne connaissent pas le jeu de baseball, les matchs durent généralement neuf manches, sauf si le match est toujours à égalité à la fin de la 9e manche. Les jeux de baseball ont donc une longueur indéterminée, ce qui signifie que je ne peux pas concevoir la base de données pour avoir seulement 9 colonnes pour les points marqués à chaque manche (enfin techniquement 18 (9 manches * 2 équipes). Une idée que j'ai eue est de sérialiser le tableau et le coder en Base64 avant de le stocker dans la base de données. Cependant, je ne sais pas si c'est une bonne technique à utiliser et je me demandais si quelqu'un avait une meilleure idée.

Au cas où cela compte, la base de données que je développe est PostgreSQL.

Toutes les suggestions sont grandement appréciées! Merci!

Philip Lombardi
la source

Réponses:

7

Tu pourrais faire ça. Il permettrait de bonnes performances pour les jeux de durée normale, tout en vous permettant de stocker également des jeux de longue durée.

CREATE TABLE InningRuns (
    GameId INT NOT NULL REFERENCES [...],
    Team CHAR(4) NOT NULL, --'Home','Away'
    Inning1 TINYINT, --Seeing how more than 255 runs are not really possible in an inning
    Inning2 TINYINT,
    [...],
    Inning9 TINYINT,
    ExtraInnings XML | TINYINT[] | VARBINARY | ETC., --Use to hold any runs in extra innings.
    PRIMARY KEY (GameId, Team)
)

Vous pouvez normaliser davantage et avoir une ligne pour chaque combinaison unique de jeu, d'équipe et de manche. Cela vous permettrait autant de manches que le type de données InningId le permettrait.

CREATE TABLE InningRuns (
    InningRunId INT IDENTITY PRIMARY KEY,
    GameId INT NOT NULL REFERENCES [...],
    Team CHAR(4) NOT NULL, --'Home','Away'
    InningId TINYINT, --Seeing how more than 255 innings might be excessive
    Runs TINYINT,
    UNIQUE (GameId, Team, InningId)
)

Edit : Je sais que PostgreSQL utilise des séquences au lieu d'IDENTITY, je ne me souviens pas de la bonne syntaxe, alors traduisez en conséquence.

Eric Humphrey - lotsahelp
la source
haha, j'aime le fait que je n'ai délibérément pas lu votre réponse avant d'avoir écrit la mienne et que nous sommes très proches les uns des autres. Agréable.
jcolebrand
Merci pour cette réponse, elle a du sens et sera la façon dont j'implémenterai le schéma de score de la boîte.
Philip Lombardi
4

Je ne pense pas qu'il y ait quelque chose de mal à avoir juste une colonne

inning_score int[]

pour 1 à 9 et au-delà. C'est l'un des rares endroits où l'utilisation d'un tableau peut être raisonnable.

Peter Eisentraut
la source
3

Donc ce que je vois ici est un peu contradictoire car les manches ne sont pas vraiment directement un attribut de jeux, sauf indirectement. Mais c'est peut-être juste moi. Personnellement, je suggérerais quelque chose de plus comme une table RunsScored et je le ferais revenir à une table GamesHeader, en quelque sorte, alors pensez à:

CREATE TABLE GamesHeader (
    GameID     INT IDENTITY(1,1),
    HomeTeamID INT,  --FK to teams table, naturally
    AwayTeamID INT,  --FK to teams table, naturally
    FinalInningsCount BYTE,  -- for faster reporting after the game is over
    FinalHomeScore BYTE,     -- for faster reporting after the game is over
    FinalAwayScore BYTE,     -- for faster reporting after the game is over
    --Other attribs
)

CREATE TABLE RunsScored (
    RunsScoredID BIGINT IDENTITY(1,1), -- for faster reverse traversal, possibly. May not be needed, this depends on your setup, as the normalization will show a composite key anyways
    PlayerID INT,   --FK to players table naturally
    GameID INT,     --FK to GamesHeader table naturally
    Inning BYTE, --wait for the payoff
    RunsEarned,     --because you may want to track this by the player ... really the problem is that there's not a single naturalized setup for this, so you may be intersecting this table to another stats table elsewhere. idk, it depends on your model. I'm going for fairly simplistic atm. Wanted to demonstrate something else entirely, but this needs to be accounted for.
     -- other attribs
)

SELECT MAX(r.Inning) FROM RunsScored r JOIN GamesHeader g ON g.GameID = r.GameID WHERE GameID = 'x'

Cela vous donnera le maximum de manche joué pour un jeu particulier, et vous pouvez affiner davantage par PlayerID -> TeamID pour trouver plus de détails si vous le souhaitez. Je ne sais pas trop ce que cela pourrait être.

J'affinerais probablement cette deuxième table pour qu'elle ne soit pas RunsScored mais quelque chose sur AtBat parce que c'est vraiment ce que vous suivez. Je voulais juste montrer comment vous pouvez dénormaliser la manche hors de la table de jeu. Je modifierais mon modèle pour qu'il coule comme ça, si c'était mon projet. HTH. YMMV.

Notez également que je suis un gars TSQL, mais je pense que les concepts exprimés ci-dessous fonctionnent assez bien pour expliquer mon concept. La sémantique des langues ne s'alignera probablement pas.

jcolebrand
la source