Если вы хотите, чтобы значения 2 столбцов в одной и той же таблице были уникальными, тогда возникает проблема с моделью данных - два или более столбцов содержат информацию одинакового типа.Возможно, лучшим решением будет переопределить DM и создать отдельные таблицы:
create table mail_address_book (serial_no number primary key /* maybe FK to somewhat */)
/
create table mail_address_entries (
serial_no number, addrno number, address varchar2(5) unique,
constraint pk_fk_mail_address_entries primary key(serial_no, addrno),
constraint fk_mail_address_entries foreign key (serial_no) references mail_address_book (serial_no))
/
В качестве обходного пути вы можете преобразовать физическую таблицу в представление, а затем использовать это представление вместо таблицы для всех запросов и операторов DML.Рассмотрим следующий пример:
create table mail_address_entries (
pk_serial_no number, addrno number, address varchar2(5) unique,
constraint pk_mail_address_entries primary key (pk_serial_no, addrno)
)
/
create or replace view mail_address_book as
select a.pk_serial_no, a.address address_a, b.address address_b
from mail_address_entries a
join mail_address_entries b on (
b.pk_serial_no = a.pk_serial_no and a.addrno = 1 and b.addrno = 2
);
create or replace trigger trig_mail_address_book
instead of insert on mail_address_book
begin
if inserting then -- the same for updating, deleting
insert into mail_address_entries values (:new.pk_serial_no, 1, :new.address_a);
insert into mail_address_entries values (:new.pk_serial_no, 2, :new.address_b);
end if;
end;
/
Вставьте тестовые данные:
create or replace type addrRow force is object (pk_serial_no number, address_a varchar2(5), address_b varchar2(5));
/
create or replace type addrRows is table of addrRow;
/
exec dbms_errlog.create_error_log (dml_table_name => 'mail_address_book');
declare
testdata addrRows;
begin
testdata := addrRows (
addrRow (1, 'A', 'B'),
addrRow (2, 'B', 'A'),
addrRow (3, 'C', 'A'),
addrRow (4, 'C', 'C'),
addrRow (5, 'C', null),
addrRow (6, null, null),
addrRow (7, 'D', 'E'),
addrRow (8, 'E', 'F')
);
for r in (select * from table (testdata)) loop
begin
insert into mail_address_book values (r.pk_serial_no, r.address_a, r.address_b);
exception when dup_val_on_index then
insert into err$_mail_address_book (pk_serial_no, address_a, address_b, ora_err_mesg$)
values (r.pk_serial_no, r.address_a, r.address_b, 'error');
end;
end loop;
end;
/
Результат:
select to_char (pk_serial_no) no, address_a a, address_b b, 'ok' msg
from mail_address_book
union all
select pk_serial_no, address_a, address_b, ora_err_mesg$ msg
from err$_mail_address_book
order by 1
;
NO A B MSG
----- ----- ----- ----------
1 A B ok
2 B A error
3 C A error
4 C C error
5 C null ok
6 null null ok
7 D E ok
8 E F error
db <> Fiddle