sql >> Database teknologi >  >> RDS >> Oracle

Implementering af et både, enten-eller, men ikke null-krav i en database

Ypercubes svar er fint, bortset fra at dette i virkeligheden kan gøres udelukkende gennem deklarativ integritet, mens man holder separate tabeller. Tricket er at kombinere udskudte cirkulære UDENLANDSKE NØGLER med en lille smule kreativ denormalisering:

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;

Indsættelse af tekst foregår på denne måde:

INSERT INTO Instruction (InstructionId, TextId) VALUES (1, 1);
INSERT INTO Text (InstructionId) VALUES (1);
COMMIT;

Indsættelse af dokument på denne måde:

INSERT INTO Instruction (InstructionId, DocumentId) VALUES (2, 2);
INSERT INTO Document (InstructionId) VALUES (2);
COMMIT;

Og indsætte både tekst og dokument sådan her:

INSERT INTO Instruction (InstructionId, TextId, DocumentId) VALUES (3, 3, 3);
INSERT INTO Text (InstructionId) VALUES (3);
INSERT INTO Document (InstructionId) VALUES (3);
COMMIT;

Men at prøve at indsætte Instruktion alene mislykkes ved forpligtelse:

INSERT INTO Instruction (InstructionId, TextId) VALUES (4, 4);
COMMIT; -- Error (FOREIGN KEY violation).

Forsøg på at indsætte den "ikke-matchede type" mislykkes også ved forpligtelse:

INSERT INTO Document (InstructionId) VALUES (1);
COMMIT; -- Error (FOREIGN KEY violation).

Og selvfølgelig, forsøg på at indsætte dårlige værdier i Instruktion mislykkes (denne gang før commit):

INSERT INTO Instruction (InstructionId, TextId) VALUES (5, 6); -- Error (CHECK violation).
INSERT INTO Instruction (InstructionId) VALUES (7); -- Error (CHECK violation).


  1. Import af en CSV til MySQL med andet datoformat

  2. MYSQL Forælder Barn Samme tabel; PHP Nest-børn i forældre som en multidimensional-array

  3. PostgreSQL unikke indekser og strengkasse

  4. rangordnede poster i mysql-tabel