前言:这是一个不好的设计,正如其他人指出。
假设:
create table a (a_id number primary key);
create table b (b_id number primary key);
create table v1
(v1_id number primary key, a_id number references a, b_id number references b);
create table v2
(v2_id number primary key, a_id number references a, b_id number references b);
create table v3
(v3_id number primary key, a_id number references a, b_id number references b);
强制规定,在任何或B从A的ID的恰好一个是必需的V_i
表的(但不是两者)是很容易的。
alter table V1
add constraint v1_check check
( (a_id is null and b_id is not null)
or (a_id is not null and b_id is null)
);
如果你想延长这一制约因素,使从A或B的ID中只有一个存在,在一个存在价值,只有一行:
create unique index v1_check_unique on v1 (coalesce (a_id, b_id));
难的是做确保来自A和B的ID存在于V_i
表中的一个且仅有一个中。这不能在DML时间完成,但可以在提交时执行。
create materialized view log on v1 with rowid;
create materialized view log on v2 with rowid;
create materialized view log on v3 with rowid;
CREATE MATERIALIZED VIEW CROSS_TABLE
REFRESH FAST ON COMMIT
AS
SELECT V1_ID AS V_ID, 'V1' AS TABLE_NAME, ROWID AS ROW_ID,
COALESCE (A_ID, B_ID) AS OTHER_ID FROM V1
UNION ALL
SELECT V2_ID AS V_ID, 'V2' AS TABLE_NAME, ROWID AS ROW_ID,
COALESCE (A_ID, B_ID) AS OTHER_ID FROM V2
UNION ALL
SELECT V3_ID AS V_ID, 'V3' AS TABLE_NAME, ROWID AS ROW_ID,
COALESCE (A_ID, B_ID) AS OTHER_ID FROM V3
/
ALTER TABLE CROSS_TABLE ADD CONSTRAINT CROSS_TABLE_UNIQUE UNIQUE (OTHER_ID);
这似乎工作 - 但不像你希望的那样令人敬畏。 Oracle无法在语句时间表上强制执行这种唯一性,因为会话A不允许考虑其他会话可能发生的任何其他更改。它只能在提交时间执行该唯一性。
以下测试用例对空表运行失败 - 并回退整个事务,因为它无法推断哪个导致失败。买者自负。
INSERT INTO A VALUES (1);
INSERT INTO B VALUES (1);
INSERT INTO V1 (V1_ID, A_ID, B_ID) VALUES (1, 1, NULL);
INSERT INTO V2 (V2_ID, A_ID, B_ID) VALUES (1, 1, NULL);
COMMIT;
我想你会需要查找表。尽管如此,我不确定最佳实现方式,但希望像Quassnoi,OMG_Ponies,gbn,martin,Joe Stefanelli或SQLMenace这样聪明的人能够投入进来! – JNK 2011-04-13 12:05:07