kel*_*hmm 3 postgresql database-design delete constraint cascade
我有一个相当标准的餐厅模型,restaurant在 PostgreSQL 数据库中有一张桌子。所有餐厅都有评分(由average、vote_count和组成vote_sum),但为了避免重复此评分模式,例如pictures我将它们移到单独的rating表中并仅存储rating_idin restaurant。
我知道 1 个评级只会被整个数据库中的 1 个其他行使用。rating在restaurant或 中删除行时如何级联删除picture?
我一直在环顾四周,但我能找到的只是设置了 a REFERENCES,但为此我需要知道将删除哪些表数据。
我知道触发器可以完成这项工作,我只是希望有更优雅的东西。
一些澄清:
REFERENCES是用于FOREIGN KEY约束的关键字(允许级联DELETE或UPDATE)。
您的数据库设计似乎存在逻辑缺陷。rating似乎是主表的细节restaurant。由于您有 1:1 的关系,您可以只在主表中包含“评级”列。如果您需要一个单独的表格,您可以restaurant_id在rating表格中包含 a而不是相反。
您的“评级”列average, vote_count and vote_sum表示另一个表vote,这些值是派生的聚合。AMATERIALIZED VIEW将是典型的解决方案。作为单独的rating表或与每个主表中的列组合...
干净的方法是rating为每个主表设置一个单独的表。然后你可以对每个都有一个 FK 约束ON DELETE CASCADE。
如果您仍然需要当前的设计,我有两个想法:
rating表中的多个 FK 列将 FK 约束反向指向正确的方向后,该表可能如下所示:
CREATE TABLE rating (
rating_id serial PRIMARY KEY
, vote_count int
, vote_sum int
, average float8
, restaurant_id int UNIQUE REFERENCES restaurant(restaurant_id)
ON UPDATE CASCADE ON DELETE CASCADE
, picture_id int UNIQUE REFERENCES picture(picture_id)
ON UPDATE CASCADE ON DELETE CASCADE
-- more references to other tables
);
Run Code Online (Sandbox Code Playgroud)
该UNIQUE约束可以加强你的1:1的要求。在每个主表中的每一行最多只能有一个行rating。还自动创建非常有用的索引。
或者,如果您有多个主表,您可能希望创建部分唯一索引,而不是从每个索引中排除不相关的行:
CREATE UNIQUE INDEX rating_restaurant_id ON rating (restaurant_id)
WHERE restaurant_id IS NOT NULL;
-- etc.
Run Code Online (Sandbox Code Playgroud)
要强制每行只有一个 FK 列是NOT NULL:
ALTER TABLE rating ADD CONSTRAINT exactly_one_fk CHECK (
(restaurant_id IS NOT NULL)::int
+ (picture_id IS NOT NULL)::int = 1); -- add more ...
Run Code Online (Sandbox Code Playgroud)
使用几个主表,看起来可能会浪费很多存储空间,但实际上并非如此。一堆 NULL 列几乎不需要任何费用。NULL 存储非常便宜:
由于您的动机是to avoid repeating this rating schema,继承对您来说可能是一个很好的解决方案。表继承的一个限制是父表的外键不是继承的——这对你的情况来说是一个优势:
CREATE TABLE rating (
rating_id serial PRIMARY KEY
, vote_count int
, vote_sum int
, average float8
);
CREATE TABLE restaurant_rating (
restaurant_id int PRIMARY KEY REFERENCES restaurant(restaurant_id)
ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (rating);
CREATE TABLE picture_rating (
picture_id int PRIMARY KEY REFERENCES picture (picture_id)
ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (rating);
-- more?
Run Code Online (Sandbox Code Playgroud)
现在您只需定义一次基本架构并从中继承。
您仍然有一个用于所有评级的公共 PK 列,并带有单个附加序列。
每个子表都将主表的 ID 添加为 PK 和 FK,从而加强您的 1:1 关系并自动提供列上的重要索引。
您可以查询主表以一次获取所有评级。如果您需要知道每一行来自哪个子表:
SELECT tableoid::regclass::text AS origin, *
FROM rating;
Run Code Online (Sandbox Code Playgroud)
您可能希望添加规则或触发器以禁止rating直接插入主表。
有关的:
| 归档时间: |
|
| 查看次数: |
10013 次 |
| 最近记录: |