我有这个概念代码(带一些注释):
IF EXISTS (SELECT * FROM information_schema.schemata WHERE schema_name = 'test')
SET NOEXEC ON
GO
-- didn't use EXEC sp_executesql for Syntax Highlighting and Code Compeltion in MSSMS
CREATE SCHEMA [test]
GO
SET NOEXEC OFF
GO
BEGIN TRANSACTION
-- child is a list
CREATE TABLE [test].[Child] (
[ChildId] BIGINT NOT NULL,
CONSTRAINT [PK_Child] PRIMARY KEY CLUSTERED ([ChildId]) WITH (IGNORE_DUP_KEY = ON)
)
-- parent is a tree
CREATE TABLE [test].[Parent] (
[ParentId] BIGINT NOT NULL,
[ParentPid] BIGINT DEFAULT NULL,
FOREIGN KEY([ParentPid]) REFERENCES [test].[Parent] ([ParentId]),
CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED ([ParentId]) WITH (IGNORE_DUP_KEY = ON)
)
-- each child can have any number of parents
CREATE TABLE [test].[ChildParent] (
[ChildId] BIGINT NOT NULL,
FOREIGN KEY([ChildId]) REFERENCES [test].[Child] ([ChildId]) ON DELETE CASCADE,
[ParentId] BIGINT NOT NULL,
FOREIGN KEY([ParentId]) REFERENCES [test].[Parent] ([ParentId]) ON DELETE CASCADE,
CONSTRAINT [PK_ChildParent] PRIMARY KEY CLUSTERED ([ChildId], [ParentId]) WITH (IGNORE_DUP_KEY = ON)
)
-- () This table is internal and used readonly, generated by a trigger on ChildParent
-- that creates associations between each Child & Parent + all the Parent's Parents
-- this way flatteting the Parent structure and making deep querying easier.
-- () ChildId + ParentPid point directly to the original Child + Parent relationship
-- that when it's deleted, it automatically deletes all the Child + Parent's Parents.
-- () I also need the table to automagically delete any row when any Child/Parent's gone.
CREATE TABLE [test].[Parent_Child] (
[ParentId] BIGINT NOT NULL,
FOREIGN KEY([ParentId]) REFERENCES [test].[Parent] ([ParentId]) ON DELETE CASCADE,
[ChildId] BIGINT NOT NULL,
FOREIGN KEY([ChildId]) REFERENCES [test].[Child] ([ChildId]) ON DELETE CASCADE,
[ParentPid] BIGINT NOT NULL,
FOREIGN KEY([ParentPid]) REFERENCES [test].[Parent] ([ParentId]) ON DELETE CASCADE,
FOREIGN KEY([ChildId], [ParentPid]) REFERENCES [test].[ChildParent] ([ChildId], [ParentId]) ON DELETE CASCADE,
CONSTRAINT [PK_Parent_Child] PRIMARY KEY CLUSTERED ([ParentId], [ChildId], [ParentPid]) WITH (IGNORE_DUP_KEY = ON)
)
COMMIT TRANSACTION
最后一张桌子不会创建I know why,即使我根本不同意,因为我无法看到这个确切的场景如何破坏任何东西或做任何事情SQLServer很难。 MySQL做了(或者至少在我上次使用它之前做了1年)这没有问题。
我也知道我在上面的(非法SQL)中做出的任何改变(删除DELETE CASCADE,删除FOREIGN KEYS)将迫使我做清理客户端(C#)
并打破我设计整齐的数据库。
考虑到我希望保留所有
Parent_Child
维护SQLServer端,以便C#客户端只读取它,是否有针对这种情况的解决方法?
PS: 考虑使用INSTEAD OF DELETE
触发器,但doc说你不能在{{1}的表上使用它}。
错误: 可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。。
答案 0 :(得分:0)
我设法为这种情况创建了一种解决方法,而没有在客户端做任何工作:
Parent
上使用触发器展平整个父级层次结构。表格结构:
CREATE TABLE [test].[ParentTree]
(
[ParentId] BIGINT NOT NULL, -- no fkey, but I double the value on column 2 so no need
[ParentPid] BIGINT NOT NULL,
FOREIGN KEY([ParentPid]) REFERENCES [dbo].[Parent] ([ParentId]) ON DELETE CASCADE,
CONSTRAINT [PK_ParentTree] PRIMARY KEY CLUSTERED ([ParentId], [ParentPid]) WITH (IGNORE_DUP_KEY = ON)
)
GO
因此,通过Parent
上的触发器,递归CTE
函数和OUTER APPLY
来实现平面层次结构,以对Parents
使用该函数。如果我有'z'
'y'
孩子'x'
的孩子,那么我的公寓桌子包含:
[Child] [Parent]
x x -- notice child is parent of child
y y -- notice child is parent of child
y x
z z -- notice child is parent of child
z y
z x
这允许我对平面数据集进行深度查询。我也可以在第2列有DELETE CASCADE
,因为我将子值加倍,所以我可以避免使用双fkeys。
要查询[Child]
[Parent]
中的所有X
(包括Y
的{{1}}和Z
{}}中的所有{/ 1}} 我只是这样做:
X
我甚至可能进一步降低复杂性,但这是我对fkey级联混乱的解决方法。
PS :复制一个fkey(所以我只能拥有一个)可能也适用于原始设计,但我对这个解决方案没问题,所以我不会尝试改变原始代码就像这样工作。