引用两个不同表的模式设计

Schema design for referencing two different tables

我有 table 条 Post 条评论,以及与 Post 条相关的评论。

PostsTable
-----
Id
Title
Content
Created

CommentsTable
-------------
Id
PostId
Content
Created

我需要 运行 分析评论和 post 以检测其中的特定词(以及从 post 或评论日期开始的时间趋势):

PostCommentDetections
--------
Id
FoundWord
PostId
CommentId

我可以使用上面的方法,如果设置了 PostId 我知道它用于 post 标题中的单词检测,如果 CommendId 用于评论检测。

然而,这需要在我的业务逻辑中仔细访问(通过 c# 和 postgres)以防止它被破坏(虽然无效,但没有什么可以阻止 PostIDCommentId同时设置,我也可以看到重复检测条目的情况。

在我开始编写此代码(以及防止重复的边缘情况)之前,有没有什么方法可以使用额外的 tables 或 approaches/considerations 来设计架构,以确保数据的完整性上面的意图是固有的?

像这样的table设计没什么大不了的,你可以使用CHECKUNIQUE约束来保持完整性。

The usual argument that the PostCommentDetections be split into 2 tables, one for PostDetections, the other for CommentDetections, comes from the application developer where they intuitively understand and can work with simple required relationships with 1:N cardinality, but tend to struggle with a table that has multiple optional FKs.

With a combined or dual FK table like this the schema itself doesn't give the developer a lot of clues as the business requirement and how the fields should be treated, they might mistakenly assume that both PostId and CommentId are required. They will need to read the requirements document to gain a better understanding... or at least they should, many a DBA has probably struggled with this and gone with the path of least resistance, that is to NOT combine the tables.

因为数据的形状,检测的写入和读取模式 记录将与您的模式中的其他 table 不同,并且由于结构简单,PostCommentDetections 的单个 table 对我这样的 DBA 来说就足够了。

  1. PostCommentDetections中的FK设为可选,也就是说他们接受NULL
  2. 添加 CHECK 约束以防止 PostId AND CommentId 处包含非空值同时,同时还要求其中之一 IS NOT NULL
  3. 添加 UNIQUE 约束以防止 PostId, CommentId, FoundWord
  4. 的重复组合

这将保持简单的 table 结构并防止开发人员弄错。在看起来像这样的 SQL 服务器中:(参见 fiddle:http://sqlfiddle.com/#!18/70be2

CREATE TABLE PostsTable (
  Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
  Title VARCHAR(100) NOT NULL,
  Content VARCHAR(2000) NULL,
  Created DateTimeOffset NOT NULL DEFAULT(SysDateTimeOffset())
);
CREATE TABLE CommentsTable (
  Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
  PostId INT NOT NULL FOREIGN KEY REFERENCES PostsTable(Id),
  Content VARCHAR(2000) NULL,
  Created DateTimeOffset NOT NULL DEFAULT(SysDateTimeOffset())
);
CREATE TABLE PostCommentDetections (
  Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
  PostId INT NULL FOREIGN KEY REFERENCES PostsTable(Id),
  CommentId INT NULL FOREIGN KEY REFERENCES CommentsTable(Id),
  FoundWord VARCHAR(50) NOT NULL,
  CHECK(PostId IS NOT NULL AND CommentId IS NULL OR PostId IS NULL AND CommentId IS NOT NULL),
  CONSTRAINT PostCommentDetections_Word_CTX UNIQUE (PostId, CommentId, FoundWord)
);

此设计的唯一主要缺点是意图不明显,但它是一个足够简单的概念,这些限制意味着只有对您的用例有效的数据才会进入检测table.


需要考虑的事情,这首先是一个好的设计想法吗?虽然您可以让它在主要应用程序数据库中运行,但我们通常会执行您的分析级别在单独的商业智能层中进行描述,数据仓库或其他一些 OLAP 或在线索引服务。

因此,虽然您 可以 直接在 SQL 中执行此操作,但您可能会发现有更好的工具或服务可以为您提供相同水平的深刻见解,而无需要自己滚动算法,请专注于确保您拥有数据,然后您可以在各种不同的维度上处理它。


(未验证)PostgreSQL 等效项:

CREATE TABLE PostsTable (
  Id SERIAL PRIMARY KEY NOT NULL,
  Title VARCHAR(100) NOT NULL,
  Content VARCHAR(2000) NULL,
  Created timestamp NOT NULL DEFAULT(NOW())
);
CREATE TABLE CommentsTable (
  Id SERIAL PRIMARY KEY NOT NULL,
  PostId INT NOT NULL,
  Content VARCHAR(2000) NULL,
  Created timestamp NOT NULL DEFAULT(NOW()),
  CONSTRAINT FK_Post FOREIGN KEY(PostId) REFERENCES PostsTable (Id)
);
CREATE TABLE PostCommentDetections (
  Id SERIAL PRIMARY KEY NOT NULL,
  PostId INT NULL,
  CommentId INT NULL,
  Content VARCHAR(2000) NULL,
  FoundWord VARCHAR(50) NOT NULL,
  CONSTRAINT FK_Post FOREIGN KEY(PostId) REFERENCES PostsTable (Id),
  CONSTRAINT FK_Comment FOREIGN KEY(CommentId) REFERENCES CommentsTable (Id),
  CHECK (PostId IS NOT NULL AND CommentId IS NULL OR PostId IS NULL AND CommentId IS NOT NULL),
  UNIQUE (PostId, CommentId, FoundWord)
);