2016-04-05 5 views
5

Ich habe eine Tabelle mit Telefonnummern, die einer Firma gehören, und eine Tabelle mit Anruflisten. Jeder Anrufdatensatz enthält Quell- und Zielnummern (nicht null). Ich habe die Integritätsbedingung, dass entweder die Quellnummer oder die Zielnummer, aber nicht beide, Nummern sein dürfen, die nicht in der Telefonnummerntabelle enthalten sind (da es sich um Zahlen handelt, die nicht von dieser Firma stammen). Mit anderen Worten, ich muss sicherstellen, dass mindestens einer von ihnen ein Fremdschlüssel für die Telefonnummerntabelle ist.SQL-Einschränkung: zwei Attribute, mindestens eine Übereinstimmung mit Fremdschlüsseln in derselben Tabelle

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

Folgende klingt wie, was ich will, ist aber nicht gültig SQL:

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

Gibt es eine Möglichkeit, dies in DDL angeben? Wenn nicht, wie würde ich einen Auslöser schreiben, um dies durchzusetzen?

Antwort

3

Editiert: Hier ist eine andere Idee DDL verwenden und nicht Trigger:

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

eine Funktion erstellen Fremdschlüssel "von Hand" zu validieren.

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; 

Wenn Sie auf 11g sind und, dann virtuelle Spalte hinzufügen, und fügen Sie Überprüfung dieser Spalte

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

Test Lassen Sie uns

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

nicht zurück zu testen konnte bis jetzt erhalten , aber das funktioniert. Vielen Dank! Ich bin in einem SQL-Kurs, aber virtuelle Spalten wurden nicht besprochen. Ist das ein allgemeiner Weg oder ein "idealer" Weg, um eine Beschränkung wie diese durchzusetzen? Ich hatte keine starke Vorliebe für DDL über Trigger, aber ich war auf jeden Fall ratlos. –

+0

Meiner Meinung nach ist es nicht sehr häufig, dass ein solcher Constraint benötigt wird, dies könnte ein Zeichen für das Design des Datenmodells sein. Für alles andere über Auslöser Vorliebe könnte ich empfehlen, "Auslöser sind böse" Google-Hits zu lesen. Was virtuelle Spalten betrifft, gibt es tatsächlich mehr, was Sie damit tun können, lesen Sie die Kolumne von Oracle Magazine 2008-März Tom Kyte als Referenz: http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28asktom -087592.html –

Verwandte Themen