使用基于函数的索引延迟唯一约束?

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上.

Gar*_*ers 5

这适用于apex.oracle.com后面的11.2.0.2.它应该在11.2.0.1中工作(可能在11.1中,但不是在10g中,因为虚拟colums是11g增强)

感谢卢卡斯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;
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)