我想对下表实施约束:
CREATE TABLE GLOBAL_LOCKS
(
RESOURCE_NAME VARCHAR2(50) NOT NULL,
IS_EXCLUSIVE CHAR(1) DEFAULT 'N' NOT NULL
)
如下:
--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,该解决方案不适用于这种情况
答案 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
时才验证约束。