我记得听过Joel Spolsky在播客014中提到他几乎没用过外键(如果我没记错的话).但是,对我而言,在整个数据库中避免重复和后续数据完整性问题似乎非常重要.
人们有一些坚实的理由为什么(避免与Stack Overflow原则一致的讨论)?
database database-design referential-integrity foreign-keys data-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.
我有什么方法可以忽略吗?
我正拼凑一个图片网站.基本模式非常简单的MySQL,但是我在尝试表示与图像相关的可能管理标志("不合适","受版权保护"等)时遇到了一些麻烦.我目前的想法如下:
tblImages (
imageID INT UNSIGNED NOT NULL AUTO_INCREMENT,
...
);
tblImageFlags (
imageFlagID INT UNSIGNED NOT NULL AUTO_INCREMENT,
imageID INT UNSIGNED NOT NULL,
flagTypeID INT UNSIGNED NOT NULL,
resolutionTypeID INT UNSIGNED NOT NULL,
...
);
luResolutionTypes (
resolutionTypeID INT UNSIGNED NOT NULL AUTO_INCREMENT,
resolutionType VARCHAR(63) NOT NULL,
...
);
Run Code Online (Sandbox Code Playgroud)
(为了便于阅读而被截断;各种外键和索引都是有序的,我发誓)
tblImageFlags.flagTypeID在标志类型的查找表上是外键的,你可以想象tblImageFlags.resolutionTypeID 应该是外键的luResolutionTypes.resolutionTypeID.手头的问题是,当首次发布一个标志时,没有逻辑解决方案类型(我很好地宣称这个NULL); 但是,如果设置了一个值,它应该是外键键到查找表.
我找不到这种情况的MySQL语法解决方法.它存在吗?最佳参赛者是:
NULL条目luResolutionTypes.resolutionTypeID(这甚至可以在AUTO_INCREMENT列中工作吗?)感谢您的见解!
PS Bonus指向任何人告诉我,在数据库的情况下,它是"索引"还是"索引".
后续行动:感谢Bill Karwin指出了表格结构中出现的语法错误(NOT NULL如果您希望它允许,请不要设置列NULL …
正如在这个问题中,我一直在阅读PoEAA,并想知道是否可以推迟参考完整性检查,直到在MySQL中提交.
想要在同一次提交中插入一堆产品和相关产品时,我遇到了这个问题.即使在事务中,当我尝试插入related_products连接表时,我也会遇到约束错误.
如果它有帮助,我正在使用PHP PDO进行数据库连接.
我很感激您提供的任何帮助.
谷歌的这一结果有点薄,但建议不容易实现.
我的具体问题是我需要在两个彼此相关的表中重新编号ID,以便表B中有一个"table_a_id"列.我不能首先对表A重新编号,因为它的B中的子节点指向旧的ID.我不能首先重新编号表B,因为它们会在创建之前指向新的ID.现在重复三到四张桌子.
当我可以"启动事务;禁用ref完整性;对ID排序;重新启用ref完整性;提交事务"时,我真的不想摆弄个人关系.Mysql和MSSQL都提供了这个功能IIRC,所以如果Postgres没有,我会感到惊讶.
谢谢!
如果我定义一个Customer和Order模型,其中Customer"有很多" Orders和Order"属于" Customer,在Rails中我们谈论Order有一个外键到Customer通过customer_id但我们并不是说这是在数据库中强制执行.
由于Rails没有将其定义为数据库级约束,因此存在数据完整性被违反的风险,可能在应用程序之外(或者如果同时收到请求,则在内部?),除非您手动在数据库中强制执行约束.
为什么Rails没有在数据库级别定义外键,或者有没有办法让Rails这样做?
class Customer < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :customer
end
ActiveRecord::Schema.define(:version => 1) do
create_table "customers", :force => true do |t|
t.string "name"
end
create_table "orders", :force => true do |t|
t.string "item_name"
t.integer "customer_id"
end
end
Run Code Online (Sandbox Code Playgroud) 我们计划在数据库中引入简单的Audit Trail,使用触发器和每个需要审计的表的单独历史表.
例如,考虑表StudentScore,它具有很少的外键(例如,StudentID,CourseID)将其链接到相应的父表(学生和课程).
Table StudentScore (
StudentScoreID, -- PK
StudentID ref Student(StudentID), -- FK to Student
CourseID ref Course(CourseID), -- FK to Course
)
Run Code Online (Sandbox Code Playgroud)
如果StudentScore需要审核,我们计划创建审核表StudentScoreHistory -
Table StudentScoreHistory (
StudentScoreHistoryID, -- PK
StudentScoreID,
StudentID,
CourseID,
AuditActionCode,
AuditDateTime,
AuditActionUserID
)
Run Code Online (Sandbox Code Playgroud)
如果StudentScore中的任何行被修改,我们会将旧行移至StudentScoreHistory.
在设计讨论期间提出的一点是在StudentHistory表中将StudentID和CourseID设为FK,以保持参照完整性.支持这一点的论据是因为我们总是主要做一个软(逻辑布尔标志)删除而不是硬删除,它有利于维护引用完整性以确保我们在审计表中没有任何孤立ID.
Table StudentScoreHistory (
StudentScoreHistoryID, -- PK
StudentScoreID,
StudentID ref Student(StudentID), -- FK to Student
CourseID ref Course(CourseID), -- FK to Course
AuditActionCode,
AuditDateTime,
AuditActionUserID
)
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎有点奇怪.我同意@Jonathan Leffler的评论,即审计记录不应该停止删除父数据.相反,如果需要,则应通过主表中的外键处理,而不是在审计表中处理.我想得到你的意见,以确保我没有错过将外键扩展到审计表的一些价值.
现在我的问题是: 在历史表中使用这些外键是一个好的设计吗?
关键参数的任何细节(性能,最佳实践,设计灵活性等)将受到高度赞赏.
为了寻找特定目的和环境的人的利益:
目的:
假设我有两个表:users和orders.用户有很多订单,所以我的订单表中自然会有一个外键user_id.
rails中的最佳实践(速度,样式和参照完整性)是什么,以确保删除用户时,所有相关订单也会被删除?我正在考虑以下选项:
案例1. :dependent => :destroy在用户模型中使用
案例2.在postgres中定义表顺序并写入
user_id integer REFERENCES users(id) ON DELETE CASCADE
Run Code Online (Sandbox Code Playgroud)
我有什么理由使用案例1吗?似乎案例2正在做我想做的一切吗?执行速度方面有区别吗?
不应强制执行引用完整性的原因之一是性能.因为Db必须根据关系验证所有更新,它只会使事情变慢,但执行和不执行的其他优缺点是什么?
因为无论如何都要在业务逻辑层中维护关系,所以它只会让db成为冗余.你对此有什么想法?
我想添加一个约束来检查相关表中的值.
我有3张桌子:
CREATE TABLE somethink_usr_rel (
user_id BIGINT NOT NULL,
stomethink_id BIGINT NOT NULL
);
CREATE TABLE usr (
id BIGINT NOT NULL,
role_id BIGINT NOT NULL
);
CREATE TABLE role (
id BIGINT NOT NULL,
type BIGINT NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
(如果你想让我对FK施加约束,请告诉我.)
我想补充一个约束somethink_usr_rel,检查type中role("两个表走"),例如:
ALTER TABLE somethink_usr_rel
ADD CONSTRAINT CH_sm_usr_type_check
CHECK (usr.role.type = 'SOME_ENUM');
Run Code Online (Sandbox Code Playgroud)
我尝试用JOINs 做但没有成功.知道如何实现它吗?
postgresql database-design referential-integrity constraints foreign-keys
database ×4
foreign-keys ×4
postgresql ×4
mysql ×2
null ×2
sql ×2
audit-trail ×1
constraints ×1