创建Id'的包含列表;使用SQL从直接/间接关系中删除

创建Id'的包含列表;使用SQL从直接/间接关系中删除,sql,sql-server,Sql,Sql Server,我有以下一组直接和间接文档依赖关系(按类型): 我需要生成整个依赖项链的包含列表,而不管我是否是插件 顶级文档ID或DependencyId 任何中间文档ID或DependencyId 底部的DocumentId或DependencyId 例如 如果我插入18…我应该得到18,16,20,22 如果我插入20或16…我应该得到18,16,20,22 如果我插入22…我应该得到18,16,20,22 保留在中间可能存在我不想包括的其他记录: 请参见下图中的白色行 我不确定发布我的代

我有以下一组直接和间接文档依赖关系(按类型):

我需要生成整个依赖项链的包含列表,而不管我是否是插件

  • 顶级文档ID或DependencyId
  • 任何中间文档ID或DependencyId
  • 底部的DocumentId或DependencyId
例如

  • 如果我插入18…我应该得到18,16,20,22
  • 如果我插入20或16…我应该得到18,16,20,22
  • 如果我插入22…我应该得到18,16,20,22
保留在中间可能存在我不想包括的其他记录:

  • 请参见下图中的白色行

我不确定发布我的代码是否有价值,因为它不起作用。不过,如果你想…我会的

设置:
下面是本地设置的代码

/****** Object:  Table [dbo].[Document]    Script Date: 2/13/2018 9:15:57 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Document](
       [Id] [int] NOT NULL,
       [ParentId] [int] NULL,
CONSTRAINT [PK_dbo.Document] PRIMARY KEY CLUSTERED 
(
       [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[DocumentDependency]    Script Date: 2/13/2018 9:15:57 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[DocumentDependency](
       [DocumentId] [int] NOT NULL,
       [DependencyId] [int] NOT NULL,
       [DependencyTypeName] [varchar](100) NOT NULL,
CONSTRAINT [PK_dbo.DocumentDependency] PRIMARY KEY CLUSTERED 
(
       [DocumentId] ASC,
       [DependencyId] ASC,
       [DependencyTypeName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (1, NULL)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (2, 1)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (3, 2)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (4, NULL)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (5, 4)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (6, 5)
GO
INSERT [dbo].[Document] ([Id], [ParentId]) VALUES (7, 5)
GO
INSERT [dbo].[DocumentDependency] ([DocumentId], [DependencyId], [DependencyTypeName]) VALUES (2, 1, N'DeviceAffinity')
GO
INSERT [dbo].[DocumentDependency] ([DocumentId], [DependencyId], [DependencyTypeName]) VALUES (3, 1, N'DeviceAffinity')
GO
INSERT [dbo].[DocumentDependency] ([DocumentId], [DependencyId], [DependencyTypeName]) VALUES (5, 4, N'DeviceAffinity')
GO
INSERT [dbo].[DocumentDependency] ([DocumentId], [DependencyId], [DependencyTypeName]) VALUES (6, 4, N'DeviceAffinity')
GO
INSERT [dbo].[DocumentDependency] ([DocumentId], [DependencyId], [DependencyTypeName]) VALUES (7, 6, N'DeviceAffinity')
GO
ALTER TABLE [dbo].[Document]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Document_dbo.Document_ParentId] FOREIGN KEY([ParentId])
REFERENCES [dbo].[Document] ([Id])
GO
ALTER TABLE [dbo].[Document] CHECK CONSTRAINT [FK_dbo.Document_dbo.Document_ParentId]
GO
ALTER TABLE [dbo].[DocumentDependency]  WITH CHECK ADD  CONSTRAINT [FK_DocumentDependency_Document] FOREIGN KEY([DocumentId])
REFERENCES [dbo].[Document] ([Id])
GO
ALTER TABLE [dbo].[DocumentDependency] CHECK CONSTRAINT [FK_DocumentDependency_Document]
GO
ALTER TABLE [dbo].[DocumentDependency]  WITH CHECK ADD  CONSTRAINT [FK_DocumentDependency_Document1] FOREIGN KEY([DependencyId])
REFERENCES [dbo].[Document] ([Id])
GO
ALTER TABLE [dbo].[DocumentDependency] CHECK CONSTRAINT [FK_DocumentDependency_Document1]
GO

首先,需要一个递归CTE来获取填充列表。这里有一种方法:

with cte as (
  select t.documentId, t.dependencyId, t.documentId as top_id
  from t
  where dependencyId is null
  union all
  select t.documentId, t.dependencyId, cte.top_id
  from cte join
       t
       on cte.dependencyId = t.documentId
)
select * from CTE 
接下来,您可以查找所需的id:

with cte as (
      select t.documentId, t.dependencyId, t.documentId as top_id
      from t
      where dependencyId is null
      union all
      select t.documentId, t.dependencyId, cte.top_id
      from cte join
           t
           on cte.dependencyId = t.documentId
    )
select *
from cte
where cte.top_id = (select cte2.top_id from cte cte2 where cte2.documentId = ?);
你可以用这个

DECLARE @Id INT = 7

;WITH CTE AS (
    SELECT *, RN = ROW_NUMBER() OVER(ORDER BY DocumentId) FROM [DocumentDependency]
), 
CTE1 AS (
    SELECT *, RN AS RL FROM CTE 
    UNION ALL
    SELECT T.*, CTE1.RL FROM CTE T 
        INNER JOIN CTE1 ON (CTE1.DependencyId IN ( T.DependencyId, T.DocumentId ) OR CTE1.DocumentId IN ( T.DependencyId, T.DocumentId ) )
        AND T.RN > CTE1.RN
)
, CTE2 AS 
(
    SELECT * FROM CTE1 WHERE RL = 
        (SELECT MIN (RL) FROM CTE1 WHERE DependencyId = @Id or DocumentId = @Id)
)
SELECT DocumentId FROM CTE2
UNION 
SELECT DependencyId FROM CTE2
@Id=7的结果:

DocumentId
-----------
4
5
6
7
@Id=2的返回结果:

DocumentId
-----------
1
2
3

很抱歉,但这不太有效……请澄清您的答案好吗?“不太有效”并不能真正帮助任何人理解正在发生的事情。对不起,上面的解决方案包括不应作为最终集一部分的记录。请看上面,谢谢,伙计……正如韦恩和加思曾经说过的,“我不配!我不配!”