返回

文章详情

在SQLite中偏爱严格表

Hacker News2026年7月11日 17:33

简而言之:我偏爱SQLite中的严格表,因为它们避免了一些数据类型的问题,例如将文本放入数字列中。SQLite有一个我认为被低估的特性:严格表。严格表帮助强制执行严格的类型,防止像将文本放入整数列这样的错误。我喜欢它们,并撰写了这篇文章以推广它们的使用!要创建一个严格表,请在其定义的末尾添加STRICT。像这样:-CREATE TABLE people (name TEXT); +CREATE TABLE people (name TEXT) STRICT; 就这样!但它能做什么呢?严格表的优势 广泛来说,严格表可以帮助强制执行严格类型,就像其他SQL引擎一样。 防止插入/更新时的类型不匹配 最重要的是,严格表使您无法在列中插入错误的类型。例如,SQLite通常允许您将文本放入INTEGER列,但使用严格表时则不允许。-- 非严格表允许您在任何地方放置任何东西。 CREATE TABLE people_nonstrict (age INTEGER); INSERT INTO people_nonstrict (age) VALUES ( 'garbage' ); -- => 正常工作 -- 严格表不允许这样做,这是我所偏好的。 CREATE TABLE people_strict (age INTEGER) STRICT; INSERT INTO people_strict (age) VALUES ( 'garbage' ); -- => 错误:无法在INTEGER列中存储TEXT值 个人而言,我认为试图将文本放入整数列,或反之亦然,是一个错误。我不希望SQLite让我犯这样的错误!对UPDATE也会进行相同的验证。值得注意的是,如果一个值可以无损地转换,它仍然会被接受。例如,字符串'123'可以完美地转换为整数,因此被允许。这两行是等效的,即使对于严格表:INSERT INTO people_strict (age) VALUES ( '123' ); INSERT INTO people_strict (age) VALUES ( 123 ); 防止在表创建时使用无效的列类型 默认情况下,您可以创建具有无效类型的列。例如,所有这些都有效,尽管它们不是有效的SQLite数据类型:-- SQLite不支持这些类型,但全部被接受。 CREATE TABLE tbl (name GARBAGE); CREATE TABLE tbl (name DATETIME); CREATE TABLE tbl (name JSON); CREATE TABLE tbl (name UUID); CREATE TABLE tbl (name BLOBB); 我认为这些不是开发人员所期望的。其中一些是拼写错误,一些是对SQLite支持哪些数据类型的误解,另一些是明显的错误。在任何这些语句后面附加STRICT都会使其出现错误。在我看来,这才是正确的行为!-- 所有这些都会引发错误,这是我所偏好的。 CREATE TABLE tbl (name GARBAGE) STRICT; CREATE TABLE tbl (name DATETIME) STRICT; CREATE TABLE tbl (name JSON) STRICT; CREATE TABLE tbl (name UUID) STRICT; CREATE TABLE tbl (name BLOBB) STRICT; 只允许INT、INTEGER、REAL、TEXT、BLOB和ANY。严格表还需要列类型,因此您无法执行CREATE TABLE tbl (name)。仍然允许使用ANY保持灵活性如果您仍然需要一个列保持灵活,可以使用ANY数据类型。顾名思义,它允许任何东西——甚至在严格表中。 CREATE TABLE tbl (value ANY) STRICT; -- 由于该列是ANY,所有这些都是有效的:INSERT INTO tbl (value) VALUES ( 123 ); INSERT INTO tbl (value) VALUES ( 'text' ); INSERT INTO tbl (value) VALUES ( 12.34 ); INSERT INTO tbl (value) VALUES (X '8647'); 我还没有找到使用它的方法,但也许你会!严格表的缺点 我更偏爱严格表,但我必须分享一些缺点。并非所有事情都更好!无法将现有表转换为严格表 我认为从一开始就使用严格性是最好的,但这并不总是可能的。不幸的是,我认为没有办法ALTER一个表使其变为严格表。我认为您必须将数据从非严格表复制到严格表中。示例如下:-- 1. 创建一个具有相同架构的新严格表 CREATE TABLE new_people (name TEXT) STRICT; -- 2. 复制数据(如果类型错误则存在风险!) INSERT INTO new_people SELECT * FROM people; -- 3. 替换旧表 DROP TABLE people; ALTER TABLE new_people RENAME TO people; 请注意,如果非严格表中包含无效数据,这可能会很棘手!例如,如果旧数据意外地在整数列中包含文本,则在进行迁移时会出现错误。您可能需要清理数据或强制转换。您可以为代码库制定一条所有新表都是严格的规则。这可能会很有用——至少您的某些表是有效的!但这也可能意味着您在表之间有不一致的验证,这可能比在所有表上进行弱验证更令人惊讶。您可以决定这是否适合您。 SQLite开发人员与我意见不同 SQLite有一个名为“灵活类型的优势”的页面,在该页面上,他们主张SQLite的灵活行为其实是好的。我不太愿意参与静态与动态的争论,但在大多数情况下我不同意。我个人遇到过很多错误,是由于意外的数据类型导致了微妙的麻烦。我宁愿这些错误大声爆炸

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡