添加具有空字符串作为默认值且非空约束的列会导致 oracle 数据库的行为不一致
Posted
技术标签:
【中文标题】添加具有空字符串作为默认值且非空约束的列会导致 oracle 数据库的行为不一致【英文标题】:Adding column with empty string as default value and not null constraint leads to inconsistent behaviour for oracle database 【发布时间】:2014-04-01 06:14:39 【问题描述】:执行此 sql 后,我无法理解 oracle 数据库中发生的情况:
CREATE TABLE EMPTYSTRING
(
COLUMNA VARCHAR2(1)
);
INSERT INTO EMPTYSTRING (COLUMNA) VALUES('X');
ALTER TABLE EMPTYSTRING ADD
(
COLUMNB VARCHAR2(1) DEFAULT '' NOT NULL
);
正如我所读,oracle 将空字符串视为空值。但是,为什么要添加一个具有默认“null”值的列和一个表示值不能为 null 合法的约束?
更重要的是,既然是合法的,那么内部如何处理? 如果我们尝试
SELECT * FROM EMPTYSTRING WHERE COLUMNB='';
SELECT * FROM EMPTYSTRING WHERE COLUMNB IS NULL;
我们没有得到任何结果。另一方面,如果我们尝试
SELECT * FROM EMPTYSTRING;
SELECT * FROM EMPTYSTRING WHERE TRIM(COLUMNB) IS NULL;
我们得到:
COLUMNA COLUMNB
------- -------
X
那么数据库中真正写的是什么?为什么会这样?
如果我们尝试插入一行而不为 COLUMNB 指定值
INSERT INTO EMPTYSTRING (COLUMNA) VALUES('Y');
我们收到“无法插入 NULL”错误,因此默认为空字符串实际上不起作用,除了我们添加 COLUMNB 之前表中的行。
【问题讨论】:
【参考方案1】:ALTER TABLE EMPTYSTRING ADD ( COLUMNB VARCHAR2(1) DEFAULT '' NOT NULL );
正如我所读,oracle 将空字符串视为空值。但是,为什么要添加一个具有默认“null”值的列和一个表示值不能为 null 合法的约束?
SGBD 不能验证您的约束是否符合逻辑。 DEFAULT 约束用于在列中插入默认值。如果未指定其他值,则默认值将添加到所有新记录。 Oracle 不检查默认值是否符合其他约束,因此如果您以这种方式编写约束,Oracle 不会发出错误信号(不会出现 ORA 错误消息)。当您尝试在未定义 COLUMNB 的值的情况下插入记录时会出现问题。
首先它会尝试将''(NULL)赋给 COLUMNB,然后它会应用为 COLUMB 定义的约束(确保值不为 NULL)。这会导致错误ORA-01407,说cannot update(...) to NULL。
SELECT * FROM EMPTYSTRING WHERE COLUMNB='';
SELECT * FROM EMPTYSTRING WHERE COLUMNB IS NULL;
在 Oracle 中,我们不能写 sth = null(表示它是否为 null)。如果我们有两个 null 值,它们仍然是不同的(null 被定义为不等于自身)。检查 COLUMNB 是否为空的唯一方法是使用 IS NULL。所以第一个不会返回任何行,即使 COLULMNB 实际上确实有空值。第二个会为 COLUMNB 返回具有空值的行,但由于 NOT NULL 约束,不存在这样的行。
【讨论】:
SELECT * FROM EMPTYSTRING WHERE COLUMNB IS NULL;如问题中所述,不返回任何行。 另外,据我了解,当新列添加默认值和非空约束时,默认值不仅应该添加到所有新记录,还应该添加到已经存在的记录。因此,如果 varchar2 的 '' 为空,那么在添加 COLUMNB 时应该会弹出错误。 当新列添加默认值和非空约束时,默认值不会添加到旧记录,它应用于新记录(除了检查是否为空的非空约束旧记录有或没有空值)。 旧记录可以在不存在的列中具有非空值?这有点奇怪,你不觉得吗?以上是关于添加具有空字符串作为默认值且非空约束的列会导致 oracle 数据库的行为不一致的主要内容,如果未能解决你的问题,请参考以下文章