Mik*_*sen 219 sql postgresql null database-design referential-integrity
我有一个这种布局的表:
CREATE TABLE Favorites
(
FavoriteId uuid NOT NULL PRIMARY KEY,
UserId uuid NOT NULL,
RecipeId uuid NOT NULL,
MenuId uuid
)
Run Code Online (Sandbox Code Playgroud)
我想创建一个类似于此的唯一约束:
ALTER TABLE Favorites
ADD CONSTRAINT Favorites_UniqueFavorite UNIQUE(UserId, MenuId, RecipeId);
Run Code Online (Sandbox Code Playgroud)
但是,这将允许多行具有相同的(UserId, RecipeId)if MenuId IS NULL.我想允许NULL在MenuId存储不具有关联菜单中的最爱,但我只希望每个用户/食谱对这些行中最多只有一个.
我到目前为止的想法是:
使用一些硬编码的UUID(例如全零)而不是null.
但是,MenuId每个用户的菜单都有一个FK约束,所以我必须为每个用户创建一个特殊的"空"菜单,这是一个麻烦.
使用触发器检查是否存在空条目.
我认为这是一个麻烦,我喜欢尽可能避免触发器.另外,我不相信他们能保证我的数据永远不会处于不良状态.
只需忘记它并检查中间件或插入函数中是否存在空条目,并且没有此约束.
我正在使用Postgres 9.0.
我有什么方法可以忽略吗?
Erw*_*ter 339
创建两个部分索引:
CREATE UNIQUE INDEX favo_3col_uni_idx ON favorites (user_id, menu_id, recipe_id)
WHERE menu_id IS NOT NULL;
CREATE UNIQUE INDEX favo_2col_uni_idx ON favorites (user_id, recipe_id)
WHERE menu_id IS NULL;
Run Code Online (Sandbox Code Playgroud)
通过这种方式,只能有一个组合(user_id, recipe_id),其中menu_id IS NULL,有效地实现所需的约束.
可能的缺点:您不能有外键引用(user_id, menu_id, recipe_id),不能CLUSTER基于部分索引,而没有匹配WHERE条件的查询不能使用部分索引.(你似乎不太可能想要一个宽三列的FK参考 - 改用PK列).
如果您需要完整的索引,您可以选择删除WHERE条件,favo_3col_uni_idx并且仍然强制执行您的要求.
现在包含整个表格的索引与另一个索引重叠并且变得更大.根据典型查询和NULL值的百分比,这可能有用,也可能没用.在极端情况下,它甚至可能有助于维护所有三个索引(两个部分索引,总数最多).
旁白:我建议不要在PostgreSQL中使用混合大小写标识符.
mu *_*ort 62
您可以在MenuId上创建一个带有合并的唯一索引:
CREATE UNIQUE INDEX
Favorites_UniqueFavorite ON Favorites
(UserId, COALESCE(MenuId, '00000000-0000-0000-0000-000000000000'), RecipeId);
Run Code Online (Sandbox Code Playgroud)
你只需要为COALESCE选择一个永远不会出现在现实生活中的UUID.在现实生活中你可能永远不会看到零UUID,但如果你是偏执狂,你可以添加一个CHECK约束(因为它们真的是为了让你......):
alter table Favorites
add constraint check
(MenuId <> '00000000-0000-0000-0000-000000000000')
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
80233 次 |
| 最近记录: |