Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Implementando um requisito de ambos, um ou outro, mas não nulo em um banco de dados


resposta do Ypercube está bem, exceto que isso pode, de fato, ser feito puramente por meio de integridade declarativa, mantendo tabelas separadas. O truque é combinar FOREIGN KEYs circulares diferidas com um pouco de desnormalização criativa:


CREATE TABLE Instruction (
    InstructionId INT PRIMARY KEY,
    TextId INT UNIQUE,
    DocumentId INT UNIQUE,
    CHECK (
        (TextId IS NOT NULL AND InstructionId = TextId)
        OR (DocumentId IS NOT NULL AND InstructionId = DocumentId)
    )
);

CREATE TABLE Text (
    InstructionId INT PRIMARY KEY,
    FOREIGN KEY (InstructionId) REFERENCES Instruction (TextId) ON DELETE CASCADE
);

CREATE TABLE Document (
    InstructionId INT PRIMARY KEY,
    FOREIGN KEY (InstructionId) REFERENCES Instruction (DocumentId) ON DELETE CASCADE
);

ALTER TABLE Instruction ADD FOREIGN KEY (TextId) REFERENCES Text DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE Instruction ADD FOREIGN KEY (DocumentId) REFERENCES Document DEFERRABLE INITIALLY DEFERRED;

A inserção de texto é feita assim:
INSERT INTO Instruction (InstructionId, TextId) VALUES (1, 1);
INSERT INTO Text (InstructionId) VALUES (1);
COMMIT;

Inserindo Documento assim:
INSERT INTO Instruction (InstructionId, DocumentId) VALUES (2, 2);
INSERT INTO Document (InstructionId) VALUES (2);
COMMIT;

E inserindo Texto e Documento assim:
INSERT INTO Instruction (InstructionId, TextId, DocumentId) VALUES (3, 3, 3);
INSERT INTO Text (InstructionId) VALUES (3);
INSERT INTO Document (InstructionId) VALUES (3);
COMMIT;

No entanto, tentar inserir a instrução sozinha falha ao cometer:
INSERT INTO Instruction (InstructionId, TextId) VALUES (4, 4);
COMMIT; -- Error (FOREIGN KEY violation).

A tentativa de inserir o "tipo incompatível" também falha ao cometer:
INSERT INTO Document (InstructionId) VALUES (1);
COMMIT; -- Error (FOREIGN KEY violation).

E, claro, tentar inserir valores incorretos na instrução falha (desta vez antes do commit):
INSERT INTO Instruction (InstructionId, TextId) VALUES (5, 6); -- Error (CHECK violation).
INSERT INTO Instruction (InstructionId) VALUES (7); -- Error (CHECK violation).