【发布时间】:2013-03-12 23:58:45
【问题描述】:
上下文
我们正在建立一个介绍博客。到数据库课程项目。
在我们的博客中,我们希望能够在Posts 上设置Labels。 Labels 不能单独存在,只有与 Posts 相关时才会存在。这样,未被任何Posts 使用的Labels 不应留在数据库中。
多个Label可以属于一个Post,多个Post可以使用一个Label。
我们同时使用 SQLite3(本地/测试)和 PostgreSQL(部署)。
实施
这是我们用来创建这两个表的 SQL(SQLite3 风格)以及关系表:
帖子
CREATE TABLE IF NOT EXISTS Posts(
id INTEGER PRIMARY KEY AUTOINCREMENT,
authorId INTEGER,
title VARCHAR(255),
content TEXT,
imageURL VARCHAR(255),
date DATETIME,
FOREIGN KEY (authorId) REFERENCES Authors(id) ON DELETE SET NULL
)
标签
CREATE TABLE IF NOT EXISTS Labels(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) UNIQUE,
-- This is not working:
FOREIGN KEY (id) REFERENCES LabelPosts(labelId) ON DELETE CASCADE
)
LabelPosts(Post [1..*] -- * Label 之间的关系)
CREATE TABLE IF NOT EXISTS LabelPosts(
postId INTEGER,
labelId INTEGER,
PRIMARY KEY (postId, labelId),
FOREIGN KEY (postId) REFERENCES Posts(id) ON DELETE CASCADE
)
问题
使用 SQLite3,当我从
LabelPosts表中删除对它的所有引用时,Labels不会从数据库中删除。我认为由于 Postgres 给出的原因,尽管 SQLite 在没有警告的情况下接受了该表。PostgreSQL 抱怨
labelId在LabelPosts中不是唯一的,这是正确的,也是必需的,因为它是多对多的:
pq: S:"ERROR" R:"transformFkeyCheckAttrs" L:"6511" C:"42830" F:"tablecmds.c"
M:"没有唯一约束匹配被引用表的给定键\"labelposts\""
所以我明白我的约束是错误的。但是我不知道如何正确地做到这一点。
【问题讨论】:
-
你可以使用触发器吗?
-
是的,但我对它们不太熟悉。
-
这看起来不像是一种非常标准的做事方法。我可以看到您要实现的目标,但是表
Labels上的外键约束不适合。你应该在LabelPosts上做CONSTRAINT fk_LabelPosts_labelId FOREIGN KEY(labelId) REFERENCES Labels(labelId)代替(在我看来)。其他一些小观察: 1. 通常建议以单数形式命名您的实体,即。在这种情况下,Label、Post和LabelPost。 2. 我建议为所有约束命名——这样以后会更容易 DROP 不必要的约束。 -
如果我切换关系上的约束,这意味着如果
Label已经存在,Post只能与Label形成关系,这不是我想要的。此外,它不会解决我希望Labels在未被任何Post引用时自动消失的问题。
标签: sql sqlite postgresql database-design many-to-many