Jef*_*emp 2 sql oracle unique-constraint
我认为这会有点深奥,但想把它扔出去,万一有人试过这样的事情,或者如果某人已经尝试过并发现它是不可能的.
我们有一个表需要对某组列进行唯一性约束,但它也有一个"软删除"指示符.已标记为"已删除"的记录不应包含在唯一性检查中.
这一切都很好,我可以使用独特的基于函数的索引轻松解决这个问题.然而,使问题复杂化的是,如果我们要在数据库中实现这个约束,它必须是延迟约束,因为Hibernate的工作方式.如果无法完成,我们将不得不省略约束,而我根本不愿意.
例如:
CREATE TABLE jkemp_test
( id NUMBER NOT NULL
, deleted_ind CHAR(1) DEFAULT 'N' NOT NULL);
CREATE UNIQUE INDEX jkemp_test_funique
ON jkemp_test
(CASE WHEN deleted_ind = 'N' THEN id END);
-- make this use the function-based index, maybe?
ALTER TABLE jkemp_test
ADD CONSTRAINT jkemp_test_unique
UNIQUE (id)
DEFERRABLE INITIALLY DEFERRED;
INSERT INTO jkemp_test VALUES (1,'N');
INSERT INTO jkemp_test VALUES (2,'N');
COMMIT;
UPDATE jkemp_test SET deleted_ind='Y' WHERE id=1;
COMMIT;
-- depending on whether the constraint is deferred or not, either
-- the insert or the commit will fail "unique constraint violated"
INSERT INTO jkemp_test VALUES (1,'N');
COMMIT;
Run Code Online (Sandbox Code Playgroud)
双赢的场景是最后一次提交成功,同时仍然允许延迟约束.(我知道唯一索引的存在意味着当前没有推迟约束.)
我们目前唯一的选择是使用应用程序实现约束,这将不可靠.此外,我们不希望过多地更改数据模型(例如,我们可以将删除的行移动到不同的表,例如JKEMP_TEST_DELETED,但这会在应用程序中涉及太多的复杂性).
这是在Oracle 11.2.0.1.0上.
这适用于apex.oracle.com后面的11.2.0.2.它应该在11.2.0.1中工作(可能在11.1中,但不是在10g中,因为虚拟colums是11g增强)
CREATE TABLE jkemp_test
( id NUMBER NOT NULL
, deleted_ind CHAR(1) DEFAULT 'N' NOT NULL);
alter table jkemp_test
ADD (active_id AS (CASE WHEN deleted_ind = 'N' THEN id END))
/
ALTER TABLE jkemp_test
ADD CONSTRAINT jkemp_test_unique
UNIQUE (active_id)
DEFERRABLE INITIALLY DEFERRED;
Run Code Online (Sandbox Code Playgroud)
您必须指定插入的列列表,因为不应指定派生列(虚拟列).我很确定hibernate对于没有触摸的列很好.
INSERT INTO jkemp_test (id, deleted_ind) VALUES (1,'N');
INSERT INTO jkemp_test (id, deleted_ind) VALUES (2,'N');
COMMIT;
UPDATE jkemp_test SET deleted_ind='Y' WHERE id=1;
COMMIT;
INSERT INTO jkemp_test (id, deleted_ind) VALUES (1,'N');
Run Code Online (Sandbox Code Playgroud)