¿Cómo implementar una entidad con un número máximo desconocido de atributos?

12

Estoy diseñando un programa de simulación de béisbol y me he encontrado con un problema con el diseño del esquema boxscore. El problema que tengo es que quiero rastrear cuántas carreras se anotan en cada entrada. La forma en que hago esto en el programa real es usar una matriz dinámica que crece para cada entrada jugada.

Para aquellos que no están familiarizados con el juego de béisbol, los juegos suelen durar nueve entradas, a menos que el juego esté empatado al final de la novena entrada. Por lo tanto, los juegos de béisbol tienen una longitud indeterminada, lo que significa que no puedo diseñar la base de datos para que solo tenga 9 columnas para las carreras anotadas en cada entrada (bueno, técnicamente 18 (9 entradas * 2 equipos). Una idea que he tenido es serializar la matriz y codificarlo como Base64 antes de almacenarlo en la base de datos. Sin embargo, no sé si es una buena técnica para usar y me preguntaba si alguien tiene una mejor idea.

En caso de que sea importante, la base de datos que estoy desarrollando es PostgreSQL.

¡Cualquier sugerencia es bienvenida! ¡Gracias!

Philip Lombardi
fuente

Respuestas:

7

Podrías hacer esto. Permitiría un buen rendimiento para juegos de duración normal, al tiempo que le permite almacenar también juegos de larga duración.

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

Podría normalizarse aún más y tener una fila para cada combinación única de juego, equipo y entrada. Esto le permitiría tantas entradas como lo permitiría el tipo de datos InningId.

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

Editar : Sé que PostgreSQL usa secuencias en lugar de IDENTIDAD, no recuerdo la sintaxis correcta, así que traduce en consecuencia.

Eric Humphrey - lotsahelp
fuente
jaja, me gusta que a propósito no leí tu respuesta hasta que escribí la mía y estamos muy cerca de la otra. Agradable.
jcolebrand
Gracias por esta respuesta, tiene sentido y será la forma en que implemente el esquema de puntuación del cuadro.
Philip Lombardi
4

No creo que haya nada malo con solo tener una columna

inning_score int[]

para 1 a 9 y más allá. Ese es uno de los pocos lugares donde el uso de una matriz puede ser razonable.

Peter Eisentraut
fuente
3

Entonces, lo que veo aquí es un poco contradictorio porque las entradas no son realmente un atributo directo de los juegos, excepto indirectamente. Pero tal vez solo soy yo. Yo personalmente sugeriría algo más como una tabla RunsScored, y hacer que se vincule a una tabla GamesHeader, de algún tipo, así que considere:

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'

Eso le dará el máximo de entrada jugado para un juego en particular, y puede refinar aún más por PlayerID -> TeamID para descubrir más detalles si lo desea. Cuáles podrían ser, no estoy seguro.

Probablemente refine esa segunda tabla para que no sea RunsScored sino algo sobre AtBat porque eso es realmente lo que estás rastreando. Solo quería mostrar cómo puedes desnormalizar la entrada fuera de la mesa de juego. Ajustaría mi modelo para que fluya así, si este fuera mi proyecto. HTH YMMV.

También tenga en cuenta que soy un chico TSQL, pero creo que los conceptos expresados ​​a continuación funcionan bastante bien para explicar mi concepto. La semántica del lenguaje probablemente no se alineará.

jcolebrand
fuente