Jak wdrożyć encję o nieznanej maksymalnej liczbie atrybutów?

12

Projektuję program do symulacji baseballu i mam problem z zaprojektowaniem schematu boxscore. Problemem jest to, że chcę śledzić liczbę przebiegów zdobytych w każdej zmianie. Sposób, w jaki to robię w rzeczywistym programie, polega na użyciu dynamicznej tablicy, która rośnie wraz z każdą odtwarzaną zmianą.

Dla tych, którzy nie znają gry w baseball, mecze trwają zwykle dziewięć rund, chyba że gra jest remisowana jeszcze pod koniec 9 rundy. Gry baseballowe mają zatem nieokreśloną długość, co oznacza, że ​​nie mogę zaprojektować bazy danych, która miałaby tylko 9 kolumn dla przebiegów zdobytych w każdej rundzie (no technicznie 18 (9 inningów * 2 drużyny). Jednym z moich pomysłów jest serializacja tablicy i koduję go jako Base64 przed zapisaniem go w bazie danych. Nie wiem jednak, czy jest to dobra technika i zastanawiałem się, czy ktoś ma lepszy pomysł.

W razie potrzeby bazą danych, którą rozwijam, jest PostgreSQL.

Wszelkie sugestie są bardzo mile widziane! Dzięki!

Philip Lombardi
źródło

Odpowiedzi:

7

Mógłbyś to zrobić. Umożliwiłoby to dobrą wydajność w przypadku gier o normalnym czasie trwania, a jednocześnie umożliwiłoby przechowywanie gier długo działających.

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

Możesz dalej normalizować i mieć wiersz dla każdej unikalnej kombinacji gry, drużyny i inningu. Pozwoliłoby to na tyle inningów, na ile pozwoliłby typ danych 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)
)

Edycja : Wiem, że PostgreSQL używa Sekwencji zamiast TOŻSAMOŚCI, nie pamiętam poprawnej składni, więc tłumacz odpowiednio.

Eric Humphrey - lotsahelp
źródło
haha, podoba mi się, że celowo nie przeczytałem twojej odpowiedzi, dopóki nie napisałem mojej i jesteśmy bardzo blisko drugiego. Ładny.
jcolebrand
Dziękuję za tę odpowiedź, ma ona sens i będzie tak, jak zaimplementuję schemat punktacji pudełka.
Philip Lombardi
4

Nie sądzę, żeby coś było nie tak z samą kolumną

inning_score int[]

dla 1 do 9 i więcej. To jedno z niewielu miejsc, w których użycie tablicy może być rozsądne.

Peter Eisentraut
źródło
3

To, co tu widzę, jest trochę sprzeczne, ponieważ inningi nie są tak naprawdę bezpośrednim atrybutem gier, z wyjątkiem pośrednich. Ale może to tylko ja. Osobiście zasugerowałbym coś bardziej jak tabelę RunsScored i chciałbym połączyć ją z powrotem z tabelą GamesHeader, więc zastanów się:

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'

To da ci maksymalną liczbę zmian rozgrywanych w konkretnej grze, a ponadto możesz udoskonalić według PlayerID -> TeamID, aby dowiedzieć się więcej szczegółów, jeśli chcesz. Co to może być, nie jestem pewien.

Prawdopodobnie poprawiłbym ten drugi stół tak, aby nie był RunsScored, ale coś o AtBat, ponieważ tak naprawdę to śledzisz. Chciałem tylko pokazać, w jaki sposób możesz zdenormalizować zmianę od stołu. Poprawiłbym mój model, aby płynął w ten sposób, gdyby to był mój projekt. HTH. YMMV.

Zauważ też, że jestem facetem TSQL, ale myślę, że przedstawione poniżej koncepcje działają całkiem dobrze w wyjaśnianiu mojej koncepcji. Semantyka językowa prawdopodobnie się nie pojawi.

jcolebrand
źródło