Как реализовать сущность с неизвестным максимальным количеством атрибутов?

12

Я разрабатываю программу симуляции бейсбола и столкнулся с проблемой при разработке схемы boxscore. Проблема, с которой я столкнулся, заключается в том, что я хочу отслеживать, сколько набранных очков забито в каждом иннинге. В реальной программе я делаю это, используя динамический массив, который увеличивается с каждым разыгрываемым иннингом.

Для тех, кто не знаком с игрой в бейсбол, игры, как правило, имеют длину в девять иннингов, если только игра не будет привязана к концу девятого тайма. Таким образом, бейсбольные игры имеют неопределенную длину, что означает, что я не могу спроектировать базу данных так, чтобы в каждом иннинге было забито только 9 столбцов для прогонов (ну, технически, 18 (9 иннингов * 2 команды). У меня была идея сериализовать массив и закодировать его как Base64 перед сохранением в базе данных. Однако я не знаю, является ли это хорошим методом для использования, и мне было интересно, есть ли у кого-нибудь идея получше.

Если это имеет значение, база данных, которую я разрабатываю, - это PostgreSQL.

Любые предложения с благодарностью! Благодарность!

Филипп Ломбарди
источник

Ответы:

7

Вы могли бы сделать это. Это обеспечит хорошую производительность для игр с нормальной продолжительностью, а также позволит вам хранить долго работающие игры.

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

Вы можете дополнительно нормализовать и иметь ряд для каждой уникальной комбинации игры, команды и иннинга. Это позволит вам столько иннингов, сколько позволит тип данных 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)
)

Редактировать : я знаю, что PostgreSQL использует последовательности вместо IDENTITY, я не помню правильный синтаксис от руки, поэтому переведите соответственно.

Эрик Хамфри - Лотсхелп
источник
хаха, мне нравится, что я специально не читал твой ответ, пока не написал свой, и мы очень близки к другому. Ницца.
Jcolebrand
Спасибо за этот ответ, он имеет смысл и будет таким, как я реализую схему оценки.
Филипп Ломбарди
4

Я не думаю, что есть что-то не так с просто колонкой

inning_score int[]

от 1 до 9 и далее. Это одно из немногих мест, где использование массива может быть разумным.

Питер Айзентраут
источник
3

Так что то, что я вижу здесь, немного противоречиво, потому что возможности на самом деле не являются прямым атрибутом игр, за исключением косвенного. Но, возможно, это только я. Я бы лично предложил что-то более похожее на таблицу RunsScored и связал бы ее с какой-нибудь таблицей GamesHeader, поэтому подумайте:

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'

Это даст вам максимальный иннинг, сыгранный для конкретной игры, и вы можете дополнительно уточнить по PlayerID -> TeamID, чтобы выяснить больше деталей, если хотите. Что это может быть, я не уверен.

Я бы, вероятно, на самом деле уточнил бы, что вторая таблица должна быть не RunsScored, а чем-то вроде AtBat, потому что это действительно то, что вы отслеживаете. Я просто хотел показать, как можно денормализовать подачу вне игрового стола. Я бы настроил свою модель так, чтобы это было, если бы это был мой проект. НТН. YMMV.

Также обратите внимание, что я парень TSQL, но я думаю, что концепции, изложенные ниже, очень хорошо объясняют мою концепцию. Семантика языка, вероятно, не будет соответствовать.

Jcolebrand
источник