关于数据库设计:数据库设计-文章、博客文章、照片、故事

Database design - articles, blog posts, photos, stories

我正在为一个网站设计一个数据库,这个网站至少有4种不同的对象类型(文章、博客文章、照片、故事),每种类型都有足够的数据需求来保证自己的表。我们希望用户能够发布这些类型的评论。评论的数据要求很简单,与评论所涉及的内容类型无关(即评论主体和作者的电子邮件)。

我希望避免为注释创建和管理4+个独立表的冗余,因此我希望能够将所有注释保存在一个表中,可能通过两列指定关系:一列指定父实体,另一列指定父行ID。

但我不知道如何实现外键,因为外键在2个表和只有2个表之间建立了关系(对吗?).

因此,考虑到所有这些,最好的方法是什么?


以下是为应用程序实现父类型/子类型表的一种方法。

首先是父类型表。它包含所有子类型通用的所有列。

1
2
3
4
5
6
CREATE TABLE publications (
  pub_id INTEGER NOT NULL PRIMARY KEY,
  pub_type CHAR(1) CHECK (pub_type IN ('A', 'B', 'P', 'S')),
  pub_url VARCHAR(64) NOT NULL UNIQUE,
  CONSTRAINT publications_superkey UNIQUE (pub_id, pub_type)
);

接下来是几个子类型表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE articles (
  pub_id INTEGER NOT NULL,
  pub_type CHAR(1) DEFAULT 'A' CHECK (pub_type = 'A'),
  placeholder CHAR(1) NOT NULL, -- placeholder for other attributes of articles
  PRIMARY KEY (pub_id, pub_type),
  FOREIGN KEY (pub_id, pub_type) REFERENCES publications (pub_id, pub_type)
);

CREATE TABLE stories (
  pub_id INTEGER NOT NULL,
  pub_type CHAR(1) DEFAULT 'S' CHECK (pub_type = 'S'),
  placeholder CHAR(1) NOT NULL, -- placeholder for other attributes of stories
  PRIMARY KEY (pub_id, pub_type),
  FOREIGN KEY (pub_id, pub_type) REFERENCES publications (pub_id, pub_type)
);

这些子类型表中的check()和foreign key约束防止行引用父类型中的错误类型的行。它有效地在子类型之间划分pub_id值,确保任何给定的pub_id都可以出现在一个而且只能出现在一个子类型表中。这就是为什么您需要对列publications.pub_id,publications.pub_type使用主键或不使用空的唯一约束的原因。

注释表很简单。考虑到它对于所有子类型都具有相同的结构,您可以引用父类型。

1
2
3
4
5
6
7
8
CREATE TABLE comments (
  pub_id INTEGER NOT NULL REFERENCES publications (pub_id),
  comment_timestamp TIMESTAMP NOT NULL DEFAULT now(),
  commenter_email VARCHAR(10) NOT NULL, -- Only allow people who have
                                        -- really short email addresses
  comment_text VARCHAR(30) NOT NULL,    -- Keep 'em short!
  PRIMARY KEY (pub_id, comment_timestamp, commenter_email)
);

添加一点数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
INSERT INTO publications VALUES
(1,'A', 'url 1 goes here'),
(2,'A', 'url 2 goes here'),
(3,'S', 'url 3 goes here');

INSERT INTO articles VALUES
(1,'A', 'A'),
(2,'A', 'B');

INSERT INTO stories VALUES
(3,'S', 'A');

INSERT INTO comments VALUES
(1, now(), '[email protected]','You''re stupid'),
(1, now(), '[email protected]', 'You''re stupid, too!');

现在,您可以创建一个视图来显示所有项目并解析联接。对于每个子类型,您都要这样做。

1
2
3
4
CREATE VIEW articles_all AS
SELECT P.*, A.placeholder
FROM publications P
INNER JOIN articles A ON (A.pub_id = P.pub_id)

您可能更喜欢"已发布的文章"这样的名称,而不是"所有文章"。

要选择一篇文章及其所有注释,您只需左键联接两个表。(但请看下面为什么你不这么做。)

1
2
3
4
SELECT A.*, C.*
FROM articles_all A
LEFT JOIN comments C ON (A.pub_id = C.pub_id)
WHERE A.pub_id = 1;

对于Web界面,您可能实际上不需要这样做,因为DBMS必须返回文章的"n"个副本,其中"n"等于注释数。但在某些应用程序中这样做确实有意义。在有意义的应用程序中,您将为每个子类型使用一个可更新的视图,而应用程序代码大多数情况下将使用可更新的视图。

父类型/子类型的更常见业务应用程序涉及"当事方"(父类型)、"组织"和"个人"(子类型、非正式公司和人员)。与上面示例中的"注释"类似,地址与父类型相关,因为所有子类型(组织和个人)都有地址。


您可以在数据库设计中使用超级类型/子类型来避免这个问题。为图像、视频、笔记创建超级类型,然后链接到超级类型。在超级类型表中保留所有公共列。

以下是几个与模型类似的问题/答案的链接:


在我看来,你最好有4+个单独的评论表。或者你可以有连接表。一张表格显示所有评论…例如:博客表、评论表、博客评论表。这样你就可以拿到你的外用钥匙了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Blog
--------
Blog_id
{other fields}

Blog_Comment
--------------
Blog_id
Comment_id


Comment
------------
Comment_id
{other fields}