例如,我们说我有一张这样的表:
CREATE TABLE people (
firstname TEXT,
lastname TEXT,
weight FLOAT,
zodiac_sign TEXT
);
前三列将具有许多不同的值,并且随着我添加更多行,它们的数量将不受限制地增长。但zodiac_sign
将始终是12个值中的一个。
我假设SQLite将为'sagittarius'
的每个实例使用11个字节(即,它不够聪明,无法推断出zodiac_sign
基本上是一个可以是枚举的枚举存储在单个字节中。)
这是否意味着,如果我要处理的行数非常重要,我应该拆分另一个这样的表:
CREATE TABLE people (
firstname TEXT,
lastname TEXT,
weight FLOAT,
zodiac_id INTEGER NOT NULL REFERENCES zodiac_signs(zodiac_id)
);
CREATE TABLE zodiac_signs (
zodiac_id INTEGER PRIMARY KEY,
name TEXT
);
对于包含少量不同值的文本列,这仍然是一个很好的做法,但它不会被限制为一些永远不会改变的值集合?例如如果我有一个出生国的专栏。
答案 0 :(得分:1)
在第一个表格设计中,字段zodiac_sign
也可以重命名为enter_anything_you_want
。良好的数据完整性实践要求每个字段的域在有意义时受到约束。例如,对于一般用途,birthdate
字段可能仅限于过去,永远不会被限制。对于DMV数据库,同一字段可能会被限制为过去至少16年。
当字段是具有固定数量的有效替代项的文本时,您可以使用检查约束来定义它:
zodiac_sign text (check zodiac_sign in( 'Leo', 'Cancer', ... )),
(我提供的示例可能不会直接转换为SQLite代码。但我想让这个更一般的讨论。)
但是,这有点尴尬,必须在包含该字段的每个表中重复。这意味着如果列表发生变化,更新新列表可能需要很多alter table
个命令。虽然十二生肖可能不太可能改变,但这通常不是这些领域可靠的方面。
实现文本值的查找表,为外键引用提供键值是一种更好的方法。它像检查约束一样限制有效值,但所有值都在一个位置,因此更改已本地化。另外,可以添加其他字段。
create table Zodiac(
ID integer not null,
Name text not null,
StartDate date,
EndDate date,
constraint PK_Zodiac primary key( ID )
);
日期会使计算哪个标志与给定日期相关联起来容易得多。 (是的,Sqlite没有本机Date数据类型 - 使用任何类型已经是您的偏好。)