I have following Oracle 19c table:
create table t (
id number primary key,
pid number not null,
tech varchar2(1)
);
and I want to impose following constraint on columns pid
and tech
:
Within group of records of same pid
, following situations of tech
values are not allowed:
null
valuesnull
and nonnull valueIn other words, for null
value of tech
there must not exist any other null
or nonnull value. For nonnull value there must not exist other null
or same value.
My questin is if this task is solvable using plain unique index
or other simple database feature. Application-based guard is the fallback if other solutions are impossible or hard to understand.
(with expected result of insertion of all rows of given pid
, all testcases with pid<10 are succeeding, pid>=90 are failing)
with t(pid, tech) as (
select 1 , null from dual union all
select 2 , 'A' from dual union all
select 3 , 'A' from dual union all
select 3 , 'B' from dual union all
select 90 , null from dual union all
select 90 , null from dual union all
select 91 , 'A' from dual union all
select 91 , 'A' from dual union all
select 92 , null from dual union all
select 92 , null from dual union all
select 92 , 'A' from dual union all
select 92 , 'B' from dual union all
select 93 , null from dual union all
select 93 , null from dual union all
select 93 , 'A' from dual union all
select 93 , 'A' from dual union all
select 94 , null from dual union all
select 94 , 'A' from dual union all
select 94 , 'A' from dual union all
select 95 , null from dual union all
select 95 , null from dual union all
select 95 , 'A' from dual union all
select 96 , null from dual union all
select 96 , 'A' from dual union all
select 97 , null from dual union all
select 97 , 'A' from dual union all
select 97 , 'B' from dual
)
select pid--, count(distinct tech) as d, count(tech) as t, count(*) as c
, case when count(*) = 1 or count(*) = count(tech) and count(*) = count(distinct tech) then 'OK' else 'ERROR' end as count_check
from t
group by pid
order by pid;
PID | COUNT_CHECK |
---|---|
1 | OK |
2 | OK |
3 | OK |
90 | ERROR |
91 | ERROR |
92 | ERROR |
93 | ERROR |
94 | ERROR |
95 | ERROR |
96 | ERROR |
97 | ERROR |
I have tried couple but with no or partial success:
vc
) so that null
s are mapped to other nonnull existing value within group or to certainly-nonexistent value (which is not problem to set and rely on). Unique index is then imposed on the (pid,vc)
tuple. In case of two null
s or null
together with nonnull, the uniqueness of such index would be violated. The problem is, the value of vc
columns needs to be computed using function operating on same table and ORA-04091: table is mutating
error appears on attempt of insert. (If window functions were allowed in virtual column expression the function would not be needed but unfortunately this is not possible.)count_check='ERROR'
as defined by count
s in test data sample. It would be great to impose such constraint on the table as a whole. I played with solution based on materialized views but ran into privilege issues and two new db objects don't seem too convincing anyway.The problem was finally solved at application level. We made a decision that benefits of guarding constraint at lower level are no worth adding and maintaining new database object. Thank you all for advices. The answer to my question is simply no.