2

我需要一个网络应用程序,该应用程序规定用户应该能够上传说明文档(.pdf、.doc、.txt)或提供说明文本。用户可以上传文档并提供文本,或者他们可以做一个或另一个,但他们必须做一些事情(不可为空)。这将如何在数据库中设计?这会被认为是一个完整的子类型(见下文)吗?

在此处输入图像描述 这是更大模式的一小部分,所以我只是发布了我认为对于这个特定问题有必要的内容。

4

4 回答 4

4

Ypercube 的回答很好,但事实上,这可以纯粹通过声明完整性来完成,同时保留单独的表格。诀窍是将延迟循环外键与一些创造性的非规范化结合起来:

在此处输入图像描述

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).
于 2012-05-06T05:55:32.653 回答
2

I think that this cannot be done with Declarative Referential Integrity alone - not if your design has these 3 separate tables.

You'll have to ensure that all Insert/Delete/Update operations are done within transactions (stored procedures) that enforce such a requirement - so no row is ever inserted or left in table Instruction without a relative row in either one of the 2 other tables.


If you don't mind having nullable fields, you could merge the 3 tables into one and use a CHECK constraint:

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)
) ;
于 2012-05-04T22:36:17.137 回答
1

如果用户提交了文本,您的应用程序可以将其保存为 .txt 文件吗?这样,您只需要担心处理文件。

于 2012-05-04T21:52:15.273 回答
0

这里感觉有点不对劲

  1. 此架构中没有UserID,因此应将其添加到 Instruction表中。

  2. 如果用户没有上传任何内容,则(应该)在表中没有该用户的条目Instruction

  3. 所以问题——如前所述——不在于对这三个表施加约束。

  4. 加载此结构时,请使用存储过程和/或事务——以确保至少填充一个子记录。但是,这与用户必须上传内容的业务需求无关。

于 2012-05-05T12:13:18.773 回答