sam*_*ris 4 sql oracle constraints
我将尝试将这种情况作为一个最小的例子:
假设我们有一张门票表,定义如下:
CREATE TABLE ticket_id_list (
ticket_id NUMBER,
issued_to VARCHAR2(100),
CONSTRAINT ticket_id_list_pk PRIMARY KEY (ticket_id)
);
Run Code Online (Sandbox Code Playgroud)
系统使用了一段时间,数据被添加到表中:
INSERT INTO ticket_id_list (ticket_id, issued_to)
VALUES (1, 'Arthur');
INSERT INTO ticket_id_list (ticket_id, issued_to)
VALUES (2, 'Ford');
Run Code Online (Sandbox Code Playgroud)
之后,弹出以下要求:
此时我们需要在票证表中存储一个参考号给其他东西.引用必须为非null.但旧记录必须有
NULL值.
(愚蠢,好像这声音,这是一个真正的要求.)
现在,如果我们这样做:
ALTER TABLE ticket_id_list
ADD ref_no VARCHAR2(6) NOT NULL;
Run Code Online (Sandbox Code Playgroud)
约束将立即被违反,我们将得到:ORA-01758: table must be empty to add mandatory (NOT NULL) column.
我们当然可以在业务逻辑中添加一个检查,但这很麻烦.由于无法解释的原因,我们无法使用默认值.有没有办法添加仅适用于新记录的NOT NULL约束?
您可以添加检查约束,其中某个日期之后的值不能为空; 就像是:
alter table ticket_id_list
add constraint nul_ref
check (ticket_id < 123456 or ref is not null);
Run Code Online (Sandbox Code Playgroud)
这确实假设ticket_id只会随着时间的推移而上升,如果你碰巧在你的表中有一个日期字段,那么使用它可能更清楚.
我发现了一个巧妙的方法:NOVALIDATE。
添加一个可为空的列:
ALTER TABLE ticket_id_list
ADD ref_no VARCHAR2(6);
Run Code Online (Sandbox Code Playgroud)
然后添加一个表约束,但一定要指定NOVALIDATE:
ALTER TABLE ticket_id_list
ADD CONSTRAINT new_ref_nonull CHECK(ref_no IS NOT NULL) NOVALIDATE;
Run Code Online (Sandbox Code Playgroud)
现在让我们检查一下:
INSERT INTO ticket_id_list (ticket_id, issued_to, ref_no)
VALUES (3, 'Zaphod', '2A4252');
1 row inserted
INSERT INTO ticket_id_list (ticket_id, issued_to, ref_no)
VALUES (4, 'Marvin', NULL);
ORA-02290: check constraint (NEW_REF_NONULL) violated
Run Code Online (Sandbox Code Playgroud)
正如预期的那样。
编辑:NOVALIDATE仅当您不需要更新旧行时才有效。如果您更新旧行,则约束将失败。不过,对于这个例子,这不是问题。