条件约束

时间:2018-11-30 03:47:07

标签: sql oracle oracle11g

我想对下表实施约束:

CREATE TABLE GLOBAL_LOCKS 
( 
  RESOURCE_NAME VARCHAR2(50) NOT NULL, 
  IS_EXCLUSIVE CHAR(1) DEFAULT 'N' NOT NULL 
)

如下:

  1. 如果IS_EXLUSIVE ='Y',RESOURCE_NAME必须是唯一的
  2. 如果所有记录的IS_EXCLUSIVE ='N',则
  3. RESOURCE_NAME可以重复

--Example 1
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'Y');
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'N');
-- should fail

--Example 2
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'N');
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'N');
-- should work

--Example 3
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'N');
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'N');
INSERT INTO GLOBAL_LOCKS(RESOURCE_NAME, IS_EXCLUSIVE)
VALUES ('MY_RESOURCE', 'Y');
-- should fail

这个想法是要在此表中维护排他和共享锁,并依靠约束来强制完整性。给定资源只能有一个互斥锁;但是给定资源可以有多个共享锁。

此问题类似于https://asktom.oracle.com/pls/apex/asktom.search?tag=how-to-enforce-conditional-unique-on-multiple-columns,但由于要求#1,该解决方案不适用于这种情况

1 个答案:

答案 0 :(得分:1)

这很复杂,因为您的要求不取决于任何给定行的值,而是取决于行的特定组合。我认为您将必须在该mview上创建实例化视图和约束。

create materialized view global_locks_validator
refresh force on commit as
select resource_name,
       max( case when is_exclusive = 'Y' then 1 else 0 end ) as max_is_exclusive,
       count(1) as resource_count
  from global_locks
 group by resource_name;

alter materialized view global_locks_validator add (
    constraint ck_validate check( max_is_exclusive = 0 or resource_count = 1 )
);

此方法的缺点是仅在发出commit时才验证约束。