我要求网络应用程序声明用户应该能够上传指令文档(.pdf,.doc,.txt)或提供说明文本。用户可以上传文档并提供文本,或者他们可以做一个或另一个,但他们必须做某事(不可为空)。如何在数据库中设计?这会被视为完整的子类型(见下文)吗?
这是较大模式的一小部分,所以我刚刚发布了我认为对于这个特定问题所必需的内容。
答案 0 :(得分:4)
Ypercube's answer很好,但实际上,这可以完全通过声明完整性来完成,同时保留单独的表。诀窍是将延迟的圆形FOREIGN KEY与一些创造性的非规范化结合起来:
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;
插入文字的方式如下:
INSERT INTO Instruction (InstructionId, TextId) VALUES (1, 1);
INSERT INTO Text (InstructionId) VALUES (1);
COMMIT;
像这样插入文档:
INSERT INTO Instruction (InstructionId, DocumentId) VALUES (2, 2);
INSERT INTO Document (InstructionId) VALUES (2);
COMMIT;
并插入文字和文档,如下所示:
INSERT INTO Instruction (InstructionId, TextId, DocumentId) VALUES (3, 3, 3);
INSERT INTO Text (InstructionId) VALUES (3);
INSERT INTO Document (InstructionId) VALUES (3);
COMMIT;
但是,在提交时尝试单独插入失败
INSERT INTO Instruction (InstructionId, TextId) VALUES (4, 4);
COMMIT; -- Error (FOREIGN KEY violation).
尝试在提交时插入“不匹配类型”失败:
INSERT INTO Document (InstructionId) VALUES (1);
COMMIT; -- Error (FOREIGN KEY violation).
当然,尝试将错误值插入指令失败(这次是在提交之前):
INSERT INTO Instruction (InstructionId, TextId) VALUES (5, 6); -- Error (CHECK violation).
INSERT INTO Instruction (InstructionId) VALUES (7); -- Error (CHECK violation).
答案 1 :(得分:2)
我认为仅凭陈述参照完整性无法做到这一点 - 如果您的设计有这3个单独的表,则不能这样做。
您必须确保所有插入/删除/更新操作都在执行此类要求的事务(存储过程)中完成 - 因此在没有相对行的情况下,不会在表Instruction
中插入或保留任何行在其他两个表中的任何一个表中。
如果您不介意拥有可空字段,可以将3个表合并为一个并使用CHECK
约束:
CREATE TABLE Instruction
( InstructionID INT NOT NULL
, Text VARCHAR(255) NULL
, Filepath VARCHAR(255) NULL
, PRIMARY KEY (InstructionID)
, CONSTRAINT Instruction_has_either_text_or_document
CHECK (Text IS NOT NULL OR FilePath IS NOT NULL)
) ;
答案 2 :(得分:1)
如果用户提交了文本,您的应用程序是否可以将其另存为.txt文件?这样你只需要担心处理文件。
答案 3 :(得分:0)
这里有点感觉
此架构中没有UserID
,因此应将其添加到
Instruction
表。
如果用户没有上传任何内容,则(应该)没有条目
对于Instruction
表中的该用户。
所以问题 - 如上所述 - 不是关于放置约束 在这三张桌子上。
加载此结构时,请使用存储过程和/或事务 - 以确保至少填充一个子记录。但是,这与用户必须上传内容的业务要求无关。