添加以空字符串作为默认值且不为空约束的列会导致 Oracle 数据库行为不一致

问题描述 投票:0回答:2

我无法理解这条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 将空字符串视为空值。但是为什么添加一个具有默认“空”值的列和一个值不能为空的约束是合法的呢?

更重要的是,既然是合法的,那么内部是如何处理的呢? 如果我们尝试

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 之前表中的行。

oracle null default-value string
2个回答
4
投票
ALTER TABLE EMPTYSTRING ADD
(
   COLUMNB VARCHAR2(1) DEFAULT '' NOT NULL
);

据我所知,oracle 将空字符串视为空值。但是为什么添加一个具有默认“空”值的列和一个值不能为空的约束是合法的呢?

SGBD 不负责验证您的约束是否具有逻辑意义。 DEFAULT 约束用于将默认值插入到列中。如果未指定其他值,则默认值将添加到所有新记录中。 Oracle 不会检查默认值是否符合其他约束,因此如果您以这种方式编写约束,Oracle 将不会发出错误信号(不会有 ORA 错误消息)。当您尝试在未定义 COLUMNB 的值的情况下插入记录时,就会出现问题。

首先它会尝试将 '' (为 NULL)赋予 COLUMNB,然后它将应用为 COLUMB 定义的约束(确保该值不为 NULL)。这将导致错误 ORA-01407,表示 cannot update(...) to NULL

从空字符串中选择 * WHERE COLUMNB='';

从空字符串中选择*,其中列为空;

在Oracle中我们不能写sth = null(表示它是否为null)。如果我们有两个 null 值,它们仍然不同(null 被定义为不等于其自身)。检查 COLUMNB 是否为空的唯一方法是使用 IS NULL。因此,即使 COLULMNB 实际上确实有空值,第一个也不会返回任何行。第二个将返回 COLUUMNB 具有空值的行,但由于 NOT NULL 约束,不存在这样的行。


0
投票

我运行了前 3 个 SQL 语句,并在运行第三个 SQL 语句来添加带有

DEFAULT '' NOT NULL
的列时,出现以下错误:

[42000][1758] ORA-01758:表必须为空才能添加强制(非空)列位置:12

此外,如果我将此

ALTER
语句修改为
DEFAULT 'H' NOT NULL
,那么表中之前的
NULL
条目将具有
H
值,与 @Blood-HaZaRd 在评论中所写的不同。

其次,如果我插入可空列

NULL
''
,此 SQL 将返回所有结果,正如 @Blood-HaZaRd 在他的答案中提到的:

SELECT * FROM EMPTYSTRING WHERE COLUMNB IS NULL;

我的Oracle版本是gvenzl/oracle-xe:21.3.0-slim。

© www.soinside.com 2019 - 2024. All rights reserved.