【问题标题】:Deferred Unique Constraint using a Function-based Index?使用基于函数的索引的延迟唯一约束?
【发布时间】:2011-03-28 01:31:38
【问题描述】:

我认为这有点深奥,但我想把它扔掉,以防有人尝试过这样的事情,或者如果有人已经尝试过并且发现这是不可能的。

我们有一个表需要对一组特定的列进行唯一性约束,但它也有一个“软删除”指示符。已标记为“已删除”的记录不应包含在唯一性检查中。

没关系,我可以使用唯一的基于函数的索引轻松解决这个问题。然而,更复杂的是,如果我们要在数据库中实现这个约束,它必须是一个延迟约束,因为 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 上。

【问题讨论】:

    标签: sql oracle unique-constraint


    【解决方案1】:

    这适用于 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');
    

    【讨论】:

      【解决方案2】:

      杰夫,

      这是实现要求的一种方法,该要求也适用于 11g 之前的版本。

      DROP MATERIALIZED VIEW MV_JKEMP ;
      DROP MATERIALIZED VIEW LOG ON jkemp_test ;
      DROP TABLE JKEMP_TEST ;
      
      CREATE TABLE jkemp_test
        ( id NUMBER NOT NULL
        , deleted_ind CHAR(1) DEFAULT 'N' NOT NULL);
      
      CREATE MATERIALIZED VIEW LOG ON jkemp_test WITH ROWID ;
      
      CREATE MATERIALIZED VIEW MV_JKEMP
      REFRESH FAST ON COMMIT
      AS
      SELECT JT1.ROWID r1, JT2.ROWID r2
      FROM JKEMP_TEST JT1, JKEMP_TEST JT2
      WHERE JT1.ID = JT2.ID
       AND JT1.DELETED_IND = JT2.DELETED_IND
       AND JT1.ROWID != JT2.ROWID
       AND JT1.DELETED_IND = 'N' ;
      
      ALTER TABLE MV_JKEMP ADD CONSTRAINT MV_CHECK CHECK (R1 IS NULL OR R2 IS NULL)
      
      
      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 AND deleted_ind = 'N';
      COMMIT;
      SELECT * FROM JKEMP_TEST ;
      SELECT * FROM MV_JKEMP;
      INSERT INTO JKEMP_TEST VALUES (1,'N');
      COMMIT;
      
      SELECT * FROM JKEMP_TEST ;
      SELECT * FROM MV_JKEMP;
      
      -- The following will succeed on the INSERT but fail on COMMIT
      INSERT INTO JKEMP_TEST VALUES (1,'N');
      COMMIT;
      
      -- The following will succeed
      INSERT INTO JKEMP_TEST VALUES (3,'N');
      COMMIT;
      
      SELECT * FROM JKEMP_TEST ;
      SELECT * FROM MV_JKEMP;
      
      -- The following will succeed
      UPDATE JKEMP_TEST SET DELETED_IND='Y' WHERE ID=1 AND DELETED_IND = 'N';
      COMMIT;
      
      SELECT * FROM JKEMP_TEST ;
      SELECT * FROM MV_JKEMP;
      
      DELETE FROM JKEMP_TEST ;
      COMMIT;
      

      以上是在 10.2.0.1 上测试的。

      【讨论】:

      • +1 测试并通过:11g 之前的版本非常好的解决方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 2011-03-18
      • 2021-11-02
      • 2011-11-23
      • 2018-12-02
      • 2019-10-26
      相关资源
      最近更新 更多