Answers:
自引用表没有错。
它是用于深度(无限)嵌套层次结构的通用数据库设计模式。
hierarchyid
类型。
死灵法师。
正确的答案是:它取决于哪个数据库引擎和哪个管理工具。
让我们举个例子:
我们有一个报表表,
一个报表可以有一个父项(菜单,如类别),
而该父项本身可以有一个父项(例如,利润中心),
等等。
标准递归关系的最简单示例,与任何自引用实体/层次结构一样。
生成的SQL-Server表为:
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports
GO
CREATE TABLE dbo.T_FMS_Reports
(
RE_UID uniqueidentifier NOT NULL
,RE_RE_UID uniqueidentifier NULL
,RE_Text nvarchar(255) NULL
,RE_Link nvarchar(400) NULL
,RE_Sort int NOT NULL
,RE_Status int NOT NULL
,PRIMARY KEY CLUSTERED ( RE_UID )
);
GO
ALTER TABLE dbo.T_FMS_Reports WITH CHECK ADD CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID)
REFERENCES dbo.T_FMS_Reports (RE_UID)
-- ON DELETE CASCADE -- here, MS-SQL has a problem
GO
ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO
但是,你得到一个问题:
当你需要删除其所有submenupoints一个menupoint,您CAN NOT集中删除级联,因为微软的SQL服务器不支持递归级联删除(在另一方面,PostgreSQL里面[但前提是图不是循环的],而MySQL根本不喜欢这种表结构,因为它不支持递归CTE。
因此,您有点用它来破坏删除完整性/功能,因此必须在您自己的代码或存储过程中(如果RDBMS支持存储过程)实施此类功能。
毫无疑问,这将炸毁任何类型的全自动动态数据导入/导出,因为您既不能简单地根据(非自引用)外键关系对所有表运行delete语句,也不能简单地进行选择*并以任意顺序为每一行创建一个插入。
例如,当您使用SSMS创建INSERT脚本时,SSMS将不会获取外键,因此确实会创建插入语句,该语句将插入具有依赖项的条目,然后再插入依赖项的父级,这会因错误而失败,因为外键就位。
但是,在具有适当工具的适当数据库管理系统(如PostgreSQL)上,这应该不是问题。仅仅因为您为RDBMS(我在看您,Microsoft; Oracle =?)和/或其工具带支付了高昂的费用,并不意味着它已被正确编程。而且,OpenSource(例如MySQL)也无法使您免受如此美妙的细节的影响。
俗话说,魔鬼在细节上。
现在,并不是说您无法解决此类问题,但是如果您的系统非常复杂(例如200多个表),我真的不建议您这样做。
另外,在通常的商业环境中(如Dilbert所描绘的那样),您将不会有那么多时间。
闭包表是一种更好的方法,尽管难度更大。
那会带来额外的好处,那就是它也适用于MySQL。
一旦实现了闭包功能,几乎就可以使它在其他地方工作。
如果关系实际上是分层关系而不是网络关系(例如物料清单是网络关系,而不是分层关系),则是一个好主意。
查询可能会很慢。为了加快速度,您可以使用闭合表。
http://karwin.blogspot.ca/2010/03/rendering-trees-with-closure-tables.html