我认为这会有点深奥,但我想把它放在那里以防万一有人尝试过这样的事情,或者如果有人已经尝试过并发现这是不可能的。
我们有一个表需要对某组列进行唯一性约束,但它也有一个“软删除”指示符。已标记为“已删除”的记录不应包含在唯一性检查中。
没关系,我可以用一个独特的基于函数的索引轻松解决这个问题。然而,让事情变得复杂的是,如果我们要在数据库中实现这个约束,它必须是一个延迟约束,因为 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;
一个双赢的场景是最后一次提交成功,同时仍然允许延迟约束。 (我知道唯一索引的存在意味着约束当前没有延迟。)
目前我们唯一的选择是使用应用程序实现约束,这并不可靠。此外,我们不想过多更改数据模型(例如,我们可以将删除的行移动到不同的表,例如 JKEMP_TEST_DELETED
,但这会使应用程序过于复杂)。
这是在 Oracle 11.2.0.1.0 上。
最佳答案
这在 apex.oracle.com 后面的 11.2.0.2 中有效。它应该在 11.2.0.1 中工作(也许在 11.1 中,但在 10g 中不行,因为虚拟列是 11g 的增强)
归功于 Lucas Jellma
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;
您必须为插入指定列列表,因为不应指定派生列(虚拟列)。我很确定 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');
关于sql - 使用基于函数的索引延迟唯一约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5453827/