这是几个(不完整的)数据库表,用于存储有关酒店房间的信息。它们存储的信息是相同的,但它们的设计不同:
将楼层信息存储在单独的列中:
| id | floor |----|------- | 1 | 1 | 2 | 1 | 3 | 2 | 4 | 2
将楼层信息存储在 ID 中。
| id |----- | 101 | 102 | 201 | 202
以表 2 的方式将语义数据存储在 ID 中总是一个糟糕的主意,或者是否存在具有更具表现力的 ID 足以证明其合理性的情况?
这是几个(不完整的)数据库表,用于存储有关酒店房间的信息。它们存储的信息是相同的,但它们的设计不同:
将楼层信息存储在单独的列中:
| id | floor
|----|-------
| 1 | 1
| 2 | 1
| 3 | 2
| 4 | 2
将楼层信息存储在 ID 中。
| id
|-----
| 101
| 102
| 201
| 202
以表 2 的方式将语义数据存储在 ID 中总是一个糟糕的主意,或者是否存在具有更具表现力的 ID 足以证明其合理性的情况?
如果要使用自然键,请使用自然键。不要命名自然键id
。
如果您使用合成键,请将其视为必须唯一但没有其他含义的任意值。
这实际上与数据的语义无关,而是关于原子性以及您是否会违反 1NF。你应该问自己的问题是:
从数据管理的角度来看,房间号是否应该被视为一个原子数据?
换句话说,您是否总是从数据库中读取(和写入)整个房间号(无论您是否在客户端代码中将其视为一个整体)?
注意:我不知道这是否是故意的,但您的场景 (1) 不包含足够的数据来重建房间号,因此与场景 (2) 相比,它模拟了不同的域。
顺便说一句,将语义数据存储在密钥中本身并不是一个坏习惯。如果某些属性或属性组合必须是唯一的,那么您必须在它们上创建一个键,无论它们是否具有内在含义。您不能用“代理”键替换该键,您只需添加代理(正如您可以想象的那样,它有其优点和缺点)。
在表的主键中包含语义肯定是个坏主意。
表中主键的用途是:
如果你把这样的语义放在主键中,那么你假设:
这些假设在未来很容易分崩离析。然后您将需要更改现有记录的主键 - 这将使它们不再是记录的标识。
这种逻辑也可以应用于其他情况。例如,您可以使用条形码作为书籍的唯一标识符,但将来您可能会拥有没有条形码的书籍。
话虽如此,我什至会更进一步,将您原来的表格更改为id
,room_number
和floor
. 由于迷信,1301
有些酒店没有房间号之类的。1302
但这并不意味着他们没有 13 楼。
最后回答你的问题——这可能并不总是一个糟糕的主意,但我想不出一个例子来说明这不是一个坏主意。
我说是的,这是一个非常糟糕的主意。id 的想法是它是可能替代多列键的行的单列唯一标识符。如果您将列称为“id”,则查看您的架构的任何人都需要一个主键。知道那个东西是地板的表示,你也失去了语义价值。
如果您没有 id 列,并且只需将该列称为“floor”,那就可以了。您关心的是,如果您需要查找特定记录,您能做到吗?如果您的特定应用程序除了查找楼层不需要任何其他信息,则继续使用“楼层”作为列名并且不要添加 ID 列。但是,如果您有一个复合键,例如 floor 和 hotel id,那么您可能希望再次添加 id 列作为“快捷方式”单列键,您可以将其用作其他表中的外键。
是的,这总是一个糟糕的主意:
我过去自己做过,并且一直后悔这样做,因为你无法预测未来,而业务和数据会以你无法预测的方式发生变化。将自己锁定在任何特定的世界观中都是危险的。事实上,我见过的每一个案例都是这样做的,它会导致很多问题。
用最重要的数字标识楼层的数字来标识房间绝对没有错。我想我住过的每一家酒店都是这样的。我敢肯定,您的表中必须有这样的房间号属性。
自己和别人的疑惑都是因为你把房间号称为“id”。房间号是一个标识符 - 大概它是唯一真正重要的房间标识符 - 但如果这是您的属性所指的,那么只需将其称为“房间号”,而不是“id”。