我有下表,表示在足球比赛期间给予球员的牌:
CREATE TABLE cards (
player_id INT,
match_id INT,
color VARCHAR(4),
minute INT,
FOREIGN KEY (player_id) REFERENCES players(id),
FOREIGN KEY (match_id) REFERENCES matches(id)
);
如您所见,其中没有主键。玩家可以在相同的比赛中在同一分钟接收两张相同颜色的牌。我认为这没关系,因为没有必要更准确地知道第二张牌是什么。
这是一个糟糕的设计吗?这有名字吗?这有什么样的正常形式吗?
答案 0 :(得分:3)
是的,一般来说,拥有没有主键的表是个坏主意。
这样做的一个原因是没有主键,如果您想要删除或更新其中一条记录(如果您有多个与您解释的数据相同的数据),则无法知道您所指的是哪条记录
示例:
player_id match_id color minute
1 100 RED 34
1 100 RED 34
2 100 YELLOW 41
3 200 RED 22
现在,想象一下你想要更新玩家1获得的第二张牌,并将其更改为黄色(或删除它)。你会怎么写这个查询?
因此,如果您希望在同一场比赛中为同一个玩家提供多条记录,则可以为每条记录创建surrogate key。否则,自然主键将是player_id和match_id的组合。
CREATE TABLE cards (
card_id INT PRIMARY KEY,
player_id INT,
match_id INT,
color VARCHAR(4),
minute INT,
FOREIGN KEY (player_id) REFERENCES players(id),
FOREIGN KEY (match_id) REFERENCES matches(id)
);
答案 1 :(得分:3)
只需添加一个新属性“NumberOfCards”,即可将{player,match,color,minute}作为密钥。
这是不好的设计吗?
是
这是否是任何形式的正常形式?
没有。每列都是可空的,并且允许重复的行,因此它不是一个正确的关系,并且不满足任何正常形式。
答案 2 :(得分:2)
让我稍微谈谈sqlvogel said ....
在关系数据库中,“table”是“关系”的数学概念的物理表示,它是元组的集。由于它是一个集合(而不是多集),它可以包含每个元组最多一次。
没有键的表允许多个相同的行/元组,因此不是关系(并且您的数据库不能再被视为“关系”)。
在您的特定情况下,您只需从现有字段中创建一个密钥,然后添加一个“数量”字段,您可以根据需要增加和减少该字段。或者,考虑一个更“细粒度”的自然键,甚至是一个“伪代理”键as proposed by Miky Dinescu,它可以让你真正区分单个卡片。
在极少数情况下,无密钥表可能有用(当数据不是很“重要”但写入性能时,例如存储调试跟踪时),但在绝大多数情况下,缺少钥匙应该是一个大红旗。