我们有一个嵌套的任务结构,其中每个任务都可以包含其他任务。任务中的任务顺序很重要,并由从<0开始的序列字段定义。 这是我的表结构:
USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Relation](
[PK_ID] [int] IDENTITY(1,1) NOT NULL,
[SourceEntityId] [uniqueidentifier] NOT NULL,
[TargetEntityId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_Relation] PRIMARY KEY CLUSTERED
(
[PK_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
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaskTable1](
[Id] [uniqueidentifier] NOT NULL,
[Title] [nvarchar](max) NULL,
[SequenceId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaskTable2](
[Id] [uniqueidentifier] NOT NULL,
[Title] [nvarchar](max) NULL,
[SequenceId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Relation] ON
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (1, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'5b266fd1-cbc8-c16a-91c4-5675a35c9ecf')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (2, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'e499ca68-8103-b8ec-06ba-110fa3f6eb5b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (4, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'645ad2eb-df10-0d5b-0526-408aad45a145')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (5, N'785227d1-393c-ae18-02e5-03ab08d577af', N'5655aeb7-b8b5-dca9-38af-37687c668c14')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (6, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'030cdefc-0e45-01e6-e2a5-a69e303bda4b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (7, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'0375c7a1-8cc5-a4c8-151c-966e4af83f73')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (8, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'785227d1-393c-ae18-02e5-03ab08d577af')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (9, N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'8324bba9-252f-bef8-c018-8b86491e2361')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (10, N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'f1cbe8a3-3285-4cf0-096d-aad0327bdb0b')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (11, N'dab00c89-961c-84dd-bb43-cffd18e63594', N'0189f0af-5045-a498-2d70-99187bf3f0ae')
GO
INSERT [dbo].[Relation] ([PK_ID], [SourceEntityId], [TargetEntityId]) VALUES (12, N'785227d1-393c-ae18-02e5-03ab08d577af', N'ffecd091-c17b-ee5f-a64d-54ea9ff65aa9')
GO
SET IDENTITY_INSERT [dbo].[Relation] OFF
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'5b266fd1-cbc8-c16a-91c4-5675a35c9ecf', N'First', 0)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'e499ca68-8103-b8ec-06ba-110fa3f6eb5b', N'Second', 1)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'0189f0af-5045-a498-2d70-99187bf3f0ae', N'Fourth', 3)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'0375c7a1-8cc5-a4c8-151c-966e4af83f73', N'Sixth', 5)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'030cdefc-0e45-01e6-e2a5-a69e303bda4b', N'Fifth', 4)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'785227d1-393c-ae18-02e5-03ab08d577af', N'Seventh', 6)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'645ad2eb-df10-0d5b-0526-408aad45a145', N'Third', 2)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'8324bba9-252f-bef8-c018-8b86491e2361', N'sub1', 0)
GO
INSERT [dbo].[TaskTable2] ([Id], [Title], [SequenceId]) VALUES (N'f1cbe8a3-3285-4cf0-096d-aad0327bdb0b', N'sub2', 1)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'ffecd091-c17b-ee5f-a64d-54ea9ff65aa9', N'sub 1', 0)
GO
INSERT [dbo].[TaskTable1] ([Id], [Title], [SequenceId]) VALUES (N'5655aeb7-b8b5-dca9-38af-37687c668c14', N'sub 2', 1)
GO
为了让他们的子任务在他们父母的正下方顺序完成任务,我尝试了以下查询无济于事:
;With TaskCTE
AS
(
select R.SourceEntityId AS ParentTask_Id, R.TargetEntityId AS Task_Id , cast(null as uniqueidentifier) AS ParentTask, 0 AS Level
, ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,0) as x
from Relation R
where (R.SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594')
UNION ALL
select R1.SourceEntityId , R1.TargetEntityId, TaskCTE.Task_Id , Level + 1
, x + ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,level+1)
from Relation R1
INNER JOIN TaskCTE
ON R1.SourceEntityId = TaskCTE.Task_Id
)
select ParentTask_Id, Task_Id, ParentTask, Level
, COALESCE(TT1.Title, TT2.Title) AS Title
, COALESCE(TT1.SequenceId, TT2.SequenceId) AS SequenceId
, x
from TaskCTE
LEFT OUTER JOIN TaskTable1 TT1
ON TaskCTE.Task_Id = TT1.Id
LEFT OUTER JOIN TaskTable2 TT2
ON TaskCTE.Task_Id = TT2.Id
order by level , SequenceId
如果您遵循所需输出的结构(如下图所示),序列**列以及**级别列必须确定排序顺序。
提前致谢
答案 0 :(得分:1)
如果您的问题是其他表中的序列字段而不是关系表,那么为什么不在运行递归之前加入它们呢?但它可能会比您的初始查询慢。这是一个样本
with cte as (
select
r.SourceEntityId, r.TargetEntityId, t.SequenceId, 0 k
from
Relation r
join (
select * from TaskTable1
union all
select * from TaskTable2
) t on r.TargetEntityId = t.id
---------------------------------------
union all select * from cte where k = 1
---------------------------------------
)
, rcte as (
select
SourceEntityId, TargetEntityId, ParentTask = cast(null as uniqueidentifier)
, SequenceId, rn = cast(row_number() over (order by SequenceId) as varchar(8000)), 1 step
from
cte
where
SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594'
union all
select
a.TargetEntityId, b.TargetEntityId, a.SourceEntityId, b.SequenceId
, cast(concat(a.rn, '.', row_number() over (partition by b.SourceEntityId order by b.SequenceId)) as varchar(8000))
, step + 1
from
rcte a
join cte b on a.TargetEntityId = b.SourceEntityId
)
select
*
from
rcte
order by rn
我没有收录您的X
列,我无法得到想要计算的内容。此外,您预期的ParentTask
和ParentTask_Id
输出值相同。应该这样吗?
答案 1 :(得分:1)
我使用与@Uzi相同的查询进行微调。我对他有同样的怀疑。@ Yasser应该清楚地显示正确输出的输出是什么,并删除不必要的列。
如果row_number仅用于订购记录,那么为什么要将其转换为varchar(8000)。此外,您可以一起避免expensive Row_number
。
利用PK_ID而不是昂贵的row_number,即使在这种情况下PK_ID不是顺序的。
如果性能是一个大问题,那么用户应该在3表中提及行数以及在何处以何种情况应用其他过滤器?
为什么数据类型为uniqueidentifier
?如果它是INT
,它会解决目的吗?
Read this
检查此查询,
WITH cte
AS (
SELECT r.PK_ID
,r.SourceEntityId
,r.TargetEntityId
,t.SequenceId,0 k
FROM #Relation r
JOIN (
SELECT id
,SequenceId
FROM #TaskTable1
UNION ALL
SELECT id
,SequenceId
FROM #TaskTable2
) t ON r.TargetEntityId = t.id
---------------------------------------
--union all select * from cte where k = 1
---------------------------------------
)
,rcte
AS (
SELECT SourceEntityId
,TargetEntityId
,ParentTask = cast(NULL AS UNIQUEIDENTIFIER)
,SequenceId
, rn = cast(row_number() over (order by SequenceId) as decimal(3,1))
--, rn = cast( SequenceId+1 as decimal(3,1))--**
,1 step
FROM cte
WHERE SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594'
UNION ALL
SELECT a.TargetEntityId
,b.TargetEntityId
,a.SourceEntityId
,b.SequenceId
,cast((a.rn+(b.SequenceId/10.0)) as decimal(3,1))
,step + 1
FROM rcte a
JOIN cte b ON a.TargetEntityId = b.SourceEntityId
)
SELECT *
FROM rcte
ORDER BY rn
--**
--SELECT *
--FROM rcte
--ORDER BY rn,st
- 第二次编辑,
据我所知,无法更改数据库。 在这种情况下,创建索引视图是非常合理的,其中任务表id是Clustered index。
select id, SequenceId from #TaskTable1
union all
select id, SequenceId from #TaskTable2
Create nonclustered index NCI_Relation_SourceID on Relation([SourceEntityId])
Create nonclustered index NCI_Relation_TargetEntityId on Relation([TargetEntityId])
你可以尝试这种组合,
将PK_ID作为聚簇索引删除,并将TargetEntityId作为聚簇索引。
您可以尝试在此查询上创建视图,
SELECT r.PK_ID
,r.SourceEntityId
,r.TargetEntityId
,t.SequenceId
FROM #Relation r
JOIN (
SELECT id
,SequenceId
FROM #TaskTable1
UNION ALL
SELECT id
,SequenceId
FROM #TaskTable2
) t ON r.TargetEntityId = t.id
答案 2 :(得分:0)
在CTE表达式中添加一个名为Hierarchy的新列,并根据此值排序结果可以解决您的需求
以下是修改后的CTE查询
;With TaskCTE AS
(
select
R.SourceEntityId AS ParentTask_Id,
R.TargetEntityId AS Task_Id , cast(null as uniqueidentifier) AS ParentTask, 0 AS Level
, ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,0) as x
,CAST( ROW_NUMBER() OVER (ORDER BY R.SourceEntityId) as varchar(max)) Hierarchy
from Relation R
where (R.SourceEntityId = 'DAB00C89-961C-84DD-BB43-CFFD18E63594')
UNION ALL
select R1.SourceEntityId , R1.TargetEntityId, TaskCTE.Task_Id , Level + 1
, x + ROW_NUMBER() OVER (ORDER BY (SELECT 100)) / power(10.0,level+1)
,CAST(Hierarchy + ':' + CAST(ROW_NUMBER() OVER (ORDER BY R1.SourceEntityId) as varchar(max)) as varchar(max)) as Hierarchy
from Relation R1
INNER JOIN TaskCTE
ON R1.SourceEntityId = TaskCTE.Task_Id
)
select ParentTask_Id, Task_Id, ParentTask, Level
, COALESCE(TT1.Title, TT2.Title) AS Title
, COALESCE(TT1.SequenceId, TT2.SequenceId) AS SequenceId
, x
,Hierarchy
from TaskCTE
LEFT OUTER JOIN TaskTable1 TT1
ON TaskCTE.Task_Id = TT1.Id
LEFT OUTER JOIN TaskTable2 TT2
ON TaskCTE.Task_Id = TT2.Id
order by Hierarchy
请注意,我添加了Hierarchy列,其值使用ROW_NUMBER()函数计算,该函数为每个任务创建唯一的整数值
您可以在refereced教程中找到此hierarchy query with SQL CTE的实现 我希望它有所帮助
我还在此处添加输出截图,以显示如何根据层次结构对数据进行排序
虽然孩子是在父母之后列出的,但是与我想要的结果没有一对一的匹配,我可以看到