I have a table with with 3 columns: A (number), B (number) and C (boolean).
I would need to create a rule that would prevent records from being created with columns A and B and with C equal to true. For example.
This would be allowed:
A B C
1 2 true
1 2 false
1 2 false
But this, no:
A B C
1 2 true
1 2 true
1 2 false
Slight variation on MarmiteBomber's approach, to avoid concatenating the values (which could cause accidental clashes with non-integer values):
create table t (a number, b number, c varchar2(5),
constraint t_chk check (c in ('true', 'false'))
);
create unique index t_unq
on t (case when c = 'true' then a end, case when c = 'true' then b end);
insert into t(a,b,c) values (1,2,'true');
1 row inserted.
insert into t(a,b,c) values (1,2,'false');
1 row inserted.
insert into t(a,b,c) values (1,2,'false');
1 row inserted.
insert into t(a,b,c) values (1,2,'true');
ORA-00001: unique constraint (MY_SCHEMA.T_UNQ) violated
select * from t;
A B C
---------- ---------- -----
1 2 true
1 2 false
1 2 false
Quick example of why non-integers (if they can exist) might be a problem:
create unique index uq_true on test(case when c = 'true' then a||'.'||b end);
insert into test(a,b,c) values (1.1, 2,'true');
1 row inserted.
insert into test(a,b,c) values (1, 1.2,'true');
ORA-00001: unique constraint (MY_SCHEMA.UQ_TRUE) violated
select * from test;
A B C
---------- ---------- -----
1.1 2 true
... because for both '1.1' ||'.'|| '2'
and '1' ||'.'|| '1.2'
resolve to the same string, '1.1.2'
.
This can also be a problem when combining string values rather than numbers. In either case you can avoid it by using a delimiter which cannot exist in either value; harder to do with strings, but with numbers any punctuation other than a period (or comma to be safe) would probably do - unless someone has a weird setting for nls_numeric_characters
...