我将尝试将这种情况作为一个最小的例子:
假设我们有一张门票表,定义如下:
CREATE TABLE ticket_id_list (
ticket_id NUMBER,
issued_to VARCHAR2(100),
CONSTRAINT ticket_id_list_pk PRIMARY KEY (ticket_id)
);
系统已使用一段时间,数据已添加到表格中:
INSERT INTO ticket_id_list (ticket_id, issued_to)
VALUES (1, 'Arthur');
INSERT INTO ticket_id_list (ticket_id, issued_to)
VALUES (2, 'Ford');
稍后,弹出以下要求:
此时我们需要在票证表中存储一个参考号给其他东西。引用必须为 非null 。但旧记录必须具有
NULL
值。
(好像这听起来很愚蠢,这是一个真正的要求。)
现在,如果我们这样做:
ALTER TABLE ticket_id_list
ADD ref_no VARCHAR2(6) NOT NULL;
约束将立即被违反,我们将获得:ORA-01758: table must be empty to add mandatory (NOT NULL) column
。
我们当然可以在业务逻辑中添加一个检查,但这很麻烦。由于无法解释的原因,我们无法使用默认值。有没有办法 添加仅适用于新记录的NOT NULL约束?
答案 0 :(得分:7)
您可以添加检查约束,其中某个日期之后的值不能为空;类似的东西:
alter table ticket_id_list
add constraint nul_ref
check (ticket_id < 123456 or ref is not null);
这确实假设ticket_id只会随着时间的推移而上升,如果您的表中碰巧有一个日期字段,那么使用它可能更清楚。
答案 1 :(得分:3)
我找到了一个巧妙的伎俩:NOVALIDATE
。
添加一个可以为空的列:
ALTER TABLE ticket_id_list
ADD ref_no VARCHAR2(6);
然后添加表格约束,但请务必指定NOVALIDATE
:
ALTER TABLE ticket_id_list
ADD CONSTRAINT new_ref_nonull CHECK(ref_no IS NOT NULL) NOVALIDATE;
现在让我们检查一下:
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
正如预期的那样。
编辑 :NOVALIDATE
仅在您不需要更新旧行时才有效。如果更新了旧行,则约束将失败。但是对于这个例子,这不是问题。
答案 2 :(得分:0)
如果要将约束设置为UNIQUE,那么它将允许所有先前的值可以为空,但所有新值都应该是唯一的,其默认值应为Null。
但是如果要将表列设为NOT NULL,则它应该包含默认值,或者应该隐式指定任何值。
答案 3 :(得分:0)
您必须将此要求视为业务逻辑,因为在您的情况下它是。
然后在触发器中实现此业务逻辑。
CREATE TRIGGER t_ticket_id_list
BEFORE INSERT ON ticket_id_list
FOR EACH ROW
BEGIN
IF (:NEW is null) THEN
RAISE_APPLICATION_ERROR(-20001, 'Cannot Insert 1 in this table');
END IF;
END;
注意 - 同样可以为SQL Server MSDN Create trigger documentations
做同样的事情