Вы можете сохранить информацию в одной таблице со значениями NULL, указывающими, что у вас нет данных до этого уровня. Вы не сможете поставить первичный ключ поверх этого, поэтому вам понадобится суррогатный ключ, но вы сможете использовать уникальное ограничение.
Например:
CREATE TABLE PenaltyCounts
(
penalty_count_id INT NOT NULL,
match_id INT NOT NULL,
period TINYINT NULL CHECK (period BETWEEN 1 AND 3),
lap SMALLINT NULL,
penalty_count SMALLINT NOT NULL,
CONSTRAINT PK_PenaltyCounts PRIMARY KEY NONCLUSTERED (penalty_count_id),
CONSTRAINT UI_PenaltyCounts UNIQUE CLUSTERED (match_id, period, lap),
CONSTRAINT CK_lap_needs_period CHECK (lap IS NULL OR period IS NOT NULL)
)
Одна проблема с этим, для которой я пока не вижу простого решения, состоит в том, как обеспечить, чтобы они ТОЛЬКО могли вводить штрафы на одном уровне. Например, они все еще могут сделать это:
INSERT INTO PenaltyCounts (penalty_count_id, match_id, period, lap, penalty_count)
VALUES (1, 1, NULL, NULL, 5)
INSERT INTO PenaltyCounts (penalty_count_id, match_id, period, lap, penalty_count)
VALUES (2, 1, 1, NULL, 3)
INSERT INTO PenaltyCounts (penalty_count_id, match_id, period, lap, penalty_count)
VALUES (3, 1, 2, NULL, 2)
Преимущество этого решения с одной таблицей заключается в том, что всю статистику можно найти, запросив одну таблицу, и значения GROUP BY будут аккуратно свернуты.
Вы также можете использовать метод отдельных таблиц, но размещать их над ними, чтобы собрать все вместе. Это по-прежнему позволяет решить проблему, указанную выше, при вводе чисел на нескольких уровнях.