2016-04-05 11 views
5

Mam tabelę numerów telefonów posiadanych przez firmę i tabelę rekordów połączeń telefonicznych. Każdy rekord połączenia zawiera (inne niż zerowy) numer źródłowy i docelowy. Otrzymałem ograniczenie integralności, że albo numer źródłowy, albo numer docelowy, ale nie oba, mogą być liczbami, których nie ma w tabeli numerów telefonów (ponieważ są to numery nie będące własnością tej firmy). Innymi słowy, muszę zapewnić, że co najmniej jeden z nich jest obcym kluczem do tabeli numerów telefonu.Ograniczenie SQL: dwa atrybuty, co najmniej jeden klucz obcy zgodny w tej samej tabeli

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) 
); 

następujące dźwięki podobne do tego, co chcę, ale nie jest poprawny SQL:

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

Czy istnieje sposób, aby określić to w DDL? Jeśli nie, w jaki sposób mogę napisać spust, aby to wymusić?

Odpowiedz

3

Zmieniano: Oto kolejny pomysł używając DDL, a nie za pomocą wyzwalacza:

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

Tworzenie funkcji w celu sprawdzenia poprawności klucza obcego „ręcznie”.

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; 

Jeśli jesteś na 11g i do góry, a następnie dodać wirtualny kolumny i dodać czek na tej kolumnie

--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'); 

testowym Miejmy

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

Nie można wrócić do testu til teraz , ale ten działa. Dzięki! Jestem na kursie SQL, ale wirtualne kolumny nie zostały omówione. Czy jest to powszechny lub "idealny" sposób egzekwowania takiego ograniczenia? Nie miałem silnej preferencji dla DDL nad wyzwalaczami, ale byłem zakłopotany w obu kierunkach. –

+0

Moim zdaniem nie jest tak często spotykane zapotrzebowanie na takie ograniczenie, może to sygnalizować problem projektowania modelu danych. W przypadku jakichkolwiek innych czynników wyzwalających preferencje mógłbym zasugerować czytanie "wyzwalacze są złe". Jeśli chodzi o kolumny wirtualne, można z nimi zrobić więcej, sprawdź w artykule Oracle Magazine 2008 marca kolumna Toma Kyte'a w celu odniesienia: http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28asktom -087592.html –

Powiązane problemy