2016-04-05 3 views
5

У меня есть таблица телефонных номеров, принадлежащих компании, и таблица записей телефонных звонков. Каждая запись вызова включает (не нулевой) номер источника и адресата. Мне присваивается ограничение целостности, что либо номер источника, либо номер получателя, но не оба, могут быть номерами, которые не указаны в таблице номеров телефонов (поскольку они являются номерами, которые не принадлежат этой компании). Другими словами, мне нужно убедиться, что по крайней мере один из них является внешним ключом к таблице номеров телефонов.Ограничение SQL: два атрибута, по крайней мере один сопоставление с внешним ключом в одной таблице

create table phonenumber (
    phonenum numeric(10,0) not null, 
    primary key (phonenum) 
); 
create table call_record (
    URID varchar(20) not null, 
    c_src numeric(10,0) not null, 
    c_dst numeric(10,0) not null, 
    primary key (URID) 
); 

следующие звуки, как то, что я хочу, но не действует SQL:

constraint call_constraint check (
    foreign key (c_src) references phonenumber (phonenum) or 
    foreign key (c_dst) references phonenumber (phonenum) 
) 

Есть ли способ указать это в DDL? Если нет, как мне написать триггер для принудительного применения этого?

ответ

3

Отредактировано: Вот еще одна идея, с помощью DDL, а не с помощью триггера:

create table phonenumber (
    phonenum numeric(10,0) not null, 
    primary key (phonenum) 
); 

Создать функцию для проверки внешнего ключа «вручную».

CREATE OR REPLACE FUNCTION call_check(p_src NUMBER, p_dst NUMBER) RETURN VARCHAR2 DETERMINISTIC IS 
BEGIN 
    FOR x IN (SELECT COUNT(*) c 
       FROM (SELECT 1 
         FROM phonenumber 
        WHERE phonenum = p_src 
        UNION ALL 
        SELECT 1 
         FROM phonenumber 
        WHERE phonenum = p_dst)) LOOP 
    IF x.c>=1 AND x.c <= 2 THEN 
     RETURN 'OK'; 
    END IF; 
    END LOOP; 
    RETURN 'NOK'; 
END; 

Если вы на 11g и выше, затем добавить виртуальный столбец и добавить проверку на этой колонке

--drop table call_record 
create table call_record (
    URID varchar(20) not null, 
    c_src numeric(10,0) not null, 
    c_dst numeric(10,0) not null, 
    call_check_col GENERATED ALWAYS AS (call_check(c_src, c_dst)), 
    primary key (URID) 
); 

ALTER TABLE call_record ADD CONSTRAINT call_check_con CHECK (call_check_col='OK'); 

протестируем

SQL>  INSERT INTO phonenumber VALUES ('123'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C1', '123', '321'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C3', '123', '123'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C2', '321', '321'); 
INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C2', '321', '321') 
ORA-02290: check constraint (TST.CALL_CHECK_CON) violated 
+0

Не удалось получить обратно тест сезам прямо сейчас , но это работает. Благодаря! Я в курсе SQL, но виртуальные столбцы не обсуждались. Является ли это обычным способом или «идеальным» способом обеспечения такого ограничения? У меня не было сильного предпочтения DDL по триггерам, но я был в тупике в любом случае. –

+0

На мой взгляд, не так уж часто возникает необходимость в таком ограничении, это может спровоцировать проблему дизайна модели данных. Для чего-либо еще более предпочтительного триггера я мог бы предложить прочитать «триггеры злые» хиты google. Что касается виртуальных столбцов, то на самом деле вы можете сделать больше с ними, проверьте колонку Oracle Magazine 2008-March Tom Kyte для справки: http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28asktom -087592.html –