Дерево исполнения

Получение иерархии дерева исполнения

На днях столкнулся с задачей, в которой была необходимость вычислить уровень вложенности определенного задания во всем дереве. В метаданных об этом информации нет, но меня заинтересовал вопрос, как строится дерево, например в таблице исполнения.

Наткнулся на процедуру модуля BackOffice , которая в своих вычислениях рассчитывает уровень вложенности задания, но в результатах выдачи его не отображало. На основе данной процедуры, я сделал свою, которая в результатах выдает необходимую мне информацию. Решил поделиться скриптом, он может быть полезным, да и в своей «базе знаний» уделю ему место.

Скрипт создания процедуры (MS SQL):

CREATE PROCEDURE [dbo].[dvadmin_GetTaskTree]
(
	@Tasks GuidList READONLY,
	@TaskGroups GuidList READONLY
)
AS
BEGIN
	SET NOCOUNT ON

	CREATE TABLE #Tasks
	(
		[TaskID] uniqueidentifier ,
		[TaskListID] uniqueidentifier,
		[ParentID] uniqueidentifier,
		[Level] int
	)

	CREATE CLUSTERED INDEX idx_tasks_taskid
	ON #Tasks ([TaskID])

	CREATE NONCLUSTERED INDEX idx_tasks_level
	ON #Tasks([Level]) include ([TaskListID])

	CREATE TABLE #TaskGroups
	(
		[TaskGroupID] uniqueidentifier,
		[TaskListID] uniqueidentifier,		
		[ParentID] uniqueidentifier,
		[Level] int
	)

	CREATE CLUSTERED INDEX idx_taskgroups_taskid
	ON #TaskGroups (TaskGroupID)

	CREATE NONCLUSTERED INDEX idx_taskgroups_level
	ON #TaskGroups([Level]) include (TaskListID)
 
	DECLARE @NullGuid uniqueidentifier = N'00000000-0000-0000-0000-000000000000', @True bit = 1, @False bit = 0
	declare @NullDate datetime, @NullText nvarchar(MAX), @NullInt int, @NullBit bit

	-- set start level and break indicator
	DECLARE @Level int = 0, @Go int = 1


	begin
		insert into #Tasks ([TaskID], [TaskListID], [Level])
		SELECT tTaskInfo.InstanceID, tTaskInfo.ChildTaskList, @Level
		FROM [dbo].[dvview_{20d21193-9f7f-4b62-8d69-272e78e1d6a8}] tTaskInfo WITH(NOLOCK)
		JOIN @Tasks tTasks ON (tTaskInfo.[InstanceID] = tTasks.[ID])              
                    
		insert into  #TaskGroups ([TaskGroupID], [TaskListID], [Level])
		SELECT tTaskGroupInfo.InstanceID, tTaskGroupInfo.TaskList, @Level
		FROM [dbo].[dvview_{7a6593bb-0bdb-4082-b43b-8f26594eff91}] tTaskGroupInfo WITH(NOLOCK)
		JOIN @TaskGroups tTaskGroups ON (tTaskGroupInfo.[InstanceID] = tTaskGroups.[ID])

		WHILE @Go > 0 
		BEGIN 
			--fetch next level
			SELECT  @Level = @Level + 1, @Go = 0

			INSERT INTO #Tasks (TaskID, TaskListID, [ParentID], [Level])
			select tTaskInfo.InstanceID, tTaskInfo.ChildTaskList, t.TaskGroupID, @Level
			from #TaskGroups t
			INNER JOIN [dbo].[dvview_{9bc6b0e9-a809-43f1-a27f-323a28d1b010}] tTaskListTasks WITH(NOLOCK) on (t.TaskListID = tTaskListTasks.InstanceID)
			INNER JOIN [dbo].[dvview_{20d21193-9f7f-4b62-8d69-272e78e1d6a8}] tTaskInfo WITH(NOLOCK, index(1) forceseek) ON (tTaskListTasks.[Task] = tTaskInfo.[InstanceID])
			WHERE t.[Level] = @Level -1

			if @@ROWCOUNT > 0
				set @Go = 1

			INSERT INTO #Tasks (TaskID, TaskListID, [ParentID], [Level])
			select tTaskInfo.InstanceID, tTaskInfo.ChildTaskList, tTaskInfo.ParentTask, @Level
			from #Tasks t
			INNER JOIN [dbo].[dvview_{20d21193-9f7f-4b62-8d69-272e78e1d6a8}] tTaskInfo WITH(NOLOCK, FORCESEEK) on (t.TaskID = tTaskInfo.ParentTask)
			WHERE t.[Level] = @Level -1

			if @@ROWCOUNT > 0
				set @Go = 1
			
			insert into  #TaskGroups ([TaskGroupID], [TaskListID], [ParentID], [Level])
			select tTaskGroupInfo.InstanceID, tTaskGroupInfo.TaskList, t.[TaskID], @Level
			from #Tasks t
			JOIN [dbo].[dvview_{4aed5aec-0ed8-4743-9c78-63d47128455e}] tTaskListTaskGroups  WITH(NOLOCK) on (t.TaskListID = tTaskListTaskGroups.InstanceID)
			JOIN [dbo].[dvview_{7a6593bb-0bdb-4082-b43b-8f26594eff91}] tTaskGroupInfo WITH(NOLOCK) on (tTaskListTaskGroups.TaskGroup = tTaskGroupInfo.InstanceID)
			WHERE t.[Level] = @Level -1
	 
			if @@ROWCOUNT > 0
				set @Go = 1

		END

		;with helpTasks([TaskID], [ParentID], [Level])
		as
		(
			select distinct [TaskID], [ParentID], [Level] from #Tasks
		),


		helpTaskGroups ([TaskGroupID], [ParentID], [Level])
		as
		(
			select distinct [TaskGroupID], [ParentID], [Level] from #TaskGroups

		),
		help ([TaskID], [TaskGroupID], [ParentItemID], [IsTaskGroup], [Level])
		as
		(
			SELECT objectsData.TaskID as [TaskID]
				,@NullGuid as [TaskGroupID]
				,objectsData.ParentID [ParentItemID]
				,@False [IsTaskGroup]
				,objectsData.Level as [LevelTask]
			FROM helpTasks objectsData
			
			union all
	
			SELECT @NullGuid as [TaskID]
				,objectsData.TaskGroupID as [TaskGroupID]
				,objectsData.ParentID as [ParentItemID]
				,@True as [IsTaskGroup]
				,objectsData.[Level] as [LevelTaskGroup]
			FROM helpTaskGroups objectsData
		)
		SELECT [TaskID], [TaskGroupID], [ParentItemID], [IsTaskGroup], [Level]
		FROM help
		ORDER BY Level ASC
	end	
END

GO

Запрос на получение данных:

DECLARE @Tasks dbo.GuidList
INSERT INTO @Tasks VALUES('2e69e7c7-6480-4413-95ae-baa1835af1e86')

EXEC [dbo].[dvadmin_GetTaskTree] @Tasks

Здесь указываем ID задания, начиная с которого необходимо определить вложенность.

Например, имеется родительское задание с идентификатором 2e69e7c7-6480-4413-95ae-baa1835af1e86, оно выделено на изображении.

По заданию создана группа заданий, по которой в свою очередь создано еще 3 подчиненных задания. В пользовательских сценариях подобное дерево заданий может быть разной вложенности. Узнаем, какие задания были на последнем уровне.

Создадим процедуру и выполним запрос на получение данных, результат будет следующим:

TaskIDTaskGroupIDParentItemIDIsTaskGroupLevel
2E69E7C7-6480-4413-95AE-BAA1835AF1E800000000-0000-0000-0000-000000000000NULL00
00000000-0000-0000-0000-00000000000023AB4F1B-3BD9-4AF2-B997-644D0B6F642B2E69E7C7-6480-4413-95AE-BAA1835AF1E811
36F496FA-2E2B-4626-BF7C-652010212ABB00000000-0000-0000-0000-00000000000023AB4F1B-3BD9-4AF2-B997-644D0B6F642B02
9E6BDAB0-CDAC-48BE-B3FB-65C5DD3A917200000000-0000-0000-0000-00000000000023AB4F1B-3BD9-4AF2-B997-644D0B6F642B02
F72AD506-052A-452F-8090-D9A06669597600000000-0000-0000-0000-00000000000023AB4F1B-3BD9-4AF2-B997-644D0B6F642B02

Из полученных данных видно, что на нижнем уровне находятся 3 задания с идентификаторами:

  • 36F496FA-2E2B-4626-BF7C-652010212ABB
  • 9E6BDAB0-CDAC-48BE-B3FB-65C5DD3A9172
  • F72AD506-052A-452F-8090-D9A066695976

При необходимости большей детализации, в скрипт процедуры можно добавить дополнительные JOIN к таблицами заданий, группы заданий, откуда взять данные о данных карточках и выполнить свою логику отбора\проверки по ним. Например, является ли задание, заданием ответственного исполнителя.

Если у вас есть альтернативные варианты вычисления уровня вложенности задания, буду рад увидеть его в комментариях.


Опубликовано

в

от


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *