SQL 列定义:默认值而不是空冗余?

Posted

技术标签:

【中文标题】SQL 列定义:默认值而不是空冗余?【英文标题】:SQL Column definition : default value and not null redundant? 【发布时间】:2012-08-05 10:12:47 【问题描述】:

我已经多次看到以下在创建/更改 DDL 语句中定义列的语法:

ALTER TABLE tbl ADD COLUMN col VARCHAR(20) NOT NULL DEFAULT "MyDefault"

问题是:既然指定了默认值,是否还需要指定该列不应接受 NULL ?换句话说,DEFAULT 不渲染 NOT NULL 是多余的吗?

【问题讨论】:

【参考方案1】:

即使使用默认值,您也始终可以使用null 覆盖列数据。

NOT NULL 限制不允许您在使用 null 值创建该行后更新该行

【讨论】:

我认为这应该改写为:“NOT NULL 限制不会让您在使用 null 值创建该行后更新该行”当然可以更新具有 NOT NULL 列的行,它们只是可以' 不更新为 null 作为该列的值。此外:我假设创建一行意味着插入一行。对于用 NOT NULL 指定的列,INSERT 语句也不能有空值。【参考方案2】:

DEFAULT 是在插入/更新语句中没有显式值的情况下将插入的值。假设,您的 DDL 没有 NOT NULL 约束:

ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT 'MyDefault'

那么你可以发布这些声明

-- 1. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B) VALUES (NULL, NULL);

-- 2. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, DEFAULT);

-- 3. This will insert 'MyDefault' into tbl.col
INSERT INTO tbl (A, B, col) DEFAULT VALUES;

-- 4. This will insert NULL into tbl.col
INSERT INTO tbl (A, B, col) VALUES (NULL, NULL, NULL);

或者,您也可以根据SQL-1992 标准在UPDATE 语句中使用DEFAULT

-- 5. This will update 'MyDefault' into tbl.col
UPDATE tbl SET col = DEFAULT;

-- 6. This will update NULL into tbl.col
UPDATE tbl SET col = NULL;

请注意,并非所有数据库都支持所有这些 SQL 标准语法。添加NOT NULL 约束将导致语句4, 6 出错,而1-3, 5 仍然是有效语句。所以回答你的问题:不,它们不是多余的。

【讨论】:

我访问了您的链接(指向您的博客文章),希望看到对查询性能的巨大影响的解释(可能带有一些数字),但只看到它简短地重申了它有影响。无意冒犯,但链接有点误导。 @SethFlowers:感谢您的指点,Seth。链接的文章在此期间进行了编辑。我会看看我是否可以链接其他东西,或者删除链接。就目前而言,您是绝对正确的,它不会为这里的答案增加任何价值。 谢谢 - 我希望我没有听起来粗鲁。我刚看到链接,就像“是的,这绝对是我想读的东西”——然后有点失望:)。 @SethFlowers:不用担心。我完全同意。拯救我:在过去的几年里,我的博客技巧大大提高了 :)【参考方案3】:

我会说不是。

如果该列确实接受空值,那么没有什么可以阻止您在字段中插入空值。据我所知,默认值仅适用于创建新行。

如果设置了非空值,则不能在字段中插入空值,因为它会引发错误。

将其视为防止空值的故障安全机制。

【讨论】:

您说的是“创建新规则”。您是否打算说“创建新行”? 我认为这是这个问题的一个更实际的答案。 @bielawski 近 8 年后,我开始纠正这个错字:) 这应该是公认的答案。 OP 要求一个简单的问题,而答案只是“不”。但是,文档需要解释和示例。【参考方案4】:

我的SQL老师说过,如果同时指定DEFAULT值和NOT NULLNULLDEFAULT应该总是在NOT NULLNULL之前表达。

像这样:

ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NOT NULL

ALTER TABLE tbl ADD COLUMN col VARCHAR(20) DEFAULT "MyDefault" NULL

【讨论】:

您好,感谢您的参与。不过,这并没有解决手头的问题,而且这两种顺序都是完全有效的。当我手动编写表格脚本时,我发现将默认值放在最后更容易,因为这样 NULL 和 NOT NULL 值会更好地对齐。 好吧,我想你也是对的。我不明白为什么我的课程明确地说明了我在答案中所写的内容。我知道我的回答并没有真正解决问题,但我发现评论不是很可读。 (主观)最佳实践和规则之间存在差异。拥有一致的风格并不是一个坏主意,但在这种特殊情况下,我个人更喜欢在 DEFAULT 之前使用 NOT NULL。无论如何,您也可以写 cmets 而不是答案,这样会更合适。 这可能无法回答问题。但这正是我想要的。谢谢。【参考方案5】:

换句话说,DEFAULT 不渲染 NOT NULL 冗余吗?

不,它不是多余的。扩展接受的答案。对于可以为空的列 col,即使定义了 DEFAULT,我们也可以插入 NULL:

CREATE TABLE t(id INT PRIMARY KEY, col INT DEFAULT 10);

-- we just inserted NULL into column with DEFAULT
INSERT INTO t(id, col) VALUES(1, NULL);

+-----+------+
| ID  | COL  |
+-----+------+
|   1 | null |
+-----+------+

Oracle 为这种情况引入了额外的语法,以默认 DEFAULT ON NULL 覆盖显式 NULL:

CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10);
-- same as
--CREATE TABLE t2(id INT PRIMARY KEY, col INT DEFAULT ON NULL 10 NOT NULL); 

INSERT INTO t2(id, col) VALUES(1, NULL);

+-----+-----+
| ID  | COL |
+-----+-----+
|  1  |  10 |
+-----+-----+

这里我们尝试插入 NULL 但取而代之的是默认值。

db<>fiddle demo

ON NULL

如果您指定 ON NULL 子句,则 Oracle 数据库会在后续 INSERT 语句尝试分配计算结果为 NULL 的值时分配 DEFAULT 列值。

当您指定 ON NULL 时,将隐式指定 NOT NULL 约束和 NOT DEFERRABLE 约束状态。

【讨论】:

【参考方案6】:

对于自 12c 以来的 Oracle,您有 DEFAULT ON NULL,这意味着 NOT NULL 约束。

ALTER TABLE tbl ADD (col VARCHAR(20) DEFAULT ON NULL 'MyDefault');

ALTER TABLE

为空

如果您指定 ON NULL 子句,则 Oracle 数据库分配 DEFAULT 列值,当随后的 INSERT 语句尝试 分配一个计算结果为 NULL 的值。

当您指定 ON NULL 时,NOT NULL 约束和 NOT DEFERRABLE 约束状态是隐式指定的。如果您指定内联 与 NOT NULL 和 NOT DEFERRABLE 冲突的约束,然后是 引发错误。

【讨论】:

以上是关于SQL 列定义:默认值而不是空冗余?的主要内容,如果未能解决你的问题,请参考以下文章

SQL:使用NULL值与默认值

由于空值而无法评估绑定时使用默认值

如何设置TextBox空字符串的默认值而不是null

如何在 phpmyadmin 中将“关系显示列”设置为默认值

Laravel 插入默认值而不是通过请求发送的数据

统一的 Firebase 远程配置仅获取默认值而不是真实值