Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 деревья - удаление  [new]
Tester666
Member

Откуда:
Сообщений: 179
Доброго времени суток!
Который день уже бьюсь над вопросом - есть таблица - с полями: id, parent_id (родитель) и т.д.
По этой таблице строится дерево - мне нужно по заданному id-у удалять всех его потомков, которые соответствуют определенным условиям.
Возможность удаления мною реализована через процедуру.
Но если добавить условия на удаления - в процессе выборки потомков : черных (которых можно удалять)
и белых (которых нельзя удалять) возникают сложности: в частности непонятно как пересчитывать удаленных
родителей потомков...
Пример дерево -
563
---564
---565 (хочу удалить эту запись и всех ее потомков, которые соответствуют условиям)
--------566 (удалить)
------------568 (удалить)
-----------------576 (оставить)
------------571 (удалить)
--------567 (удалить)
--------569 (оставить)
--------577 (оставить)
--------578 (оставить)
-------------584 (оставить)
Привожу примерный текст процедуры -
if object_id('procc', 'P') is not null drop procedure dbo.procc  
go

create procedure procc  
  (	
	@inId   int       -- Идентификатор 
  )
  with --encryption,
  execute as owner
as
  set nocount on
  --временные таблицы
  --потомки, которых нужно удалить
  declare @res table (inId int, 
				      inIdParent int, 
				      ilevel int, 
				      inTaskState int, 
				      inChildNum int)		
  --потомки, которых нужно сохранить				      	
  declare @save table (inId int, 
                       inIdParent int, 
                       ilevel int, 
                       inTaskState int, 
                       inChildNum int)				  				  	  
  declare @ilevel int --Уровень вложенности

  set @ilevel = 0	--устанавливаем корневой уровень
  --определяем корень
  insert into @res (inId,
					inIdParent, 
                    ilevel, 
                    inTaskState, 
                    inChildNum)
  select inid, 
		 inIdParent,
         @ilevel, 
         inTaskState, 
         inChildNum 
  from dbo.suTasks where inid = @inId

  while @@rowcount > 0 
  begin
	set @ilevel = @ilevel + 1
	--заполняем временную таблицу в порядке вложенности
	insert into @res (inid, 
					  inIdParent,
					  ilevel, 
					  inTaskState, 
					  inChildNum)
    select s.inid, 
           s.inIdParent, 
           @ilevel, 
           s.inTaskState, 
           s.inChildNum
    from (select inId from @res where ilevel = @ilevel - 1) c inner join dbo.suTasks s 
		on c.inId = s.inIdParent	
  end
  begin tran 
    --заполняем временную таблицу (кроме задач в состоянии "Новая")
    insert into @save (inid, 
					   inIdParent,
					   ilevel, 
					   inTaskState, 
					   inChildNum)
    select inid, 
		   inIdParent, 
		   ilevel, 
		   inTaskState, 
		   inChildNum 
    from @res 
    where inTaskState <> 0
    if @@error <> 0 goto ErrorHandler  
 
    --на каждом уровне могут быть разные родители:
    --как заменить удаленных родителей неудаленными родителями более верхнего уровня?   
    --если родители потомка удалены, переносим потомка на верхний уровень
    --ВОТ ЭТОТ МОМЕНТ НЕ ЗНАЮ КАК СДЕЛАТЬ!!!

    --обновленных родителей из @save обновляем в самой таблице...
 
    --удаляем скопированные для сохранения данные
    delete from @res 
    from @res  r inner join @save s on r.inId = s.inId
    if @@error <> 0 goto ErrorHandler
 
    --!!Должны удаляться все потомки
    delete from dbo.suTasks 
    from dbo.suTasks t inner join @res r on t.inId = r.inId
    if @@error <> 0 goto ErrorHandler
  commit tran
  return 0
ErrorHandler:
  if @@trancount > 0  rollback tran
  return 1   
go



1 июл 11, 14:51    [10906719]     Ответить | Цитировать Сообщить модератору
 Re: деревья - удаление  [new]
USBcab
Member

Откуда:
Сообщений: 48
Перед удалением можно всем потомкам присваивать parent_id удаляемой записи(если правильно понял задачу:) ).
1 июл 11, 15:19    [10907070]     Ответить | Цитировать Сообщить модератору
 Re: деревья - удаление  [new]
Владимир СА
Member

Откуда:
Сообщений: 7915
Tester666
...
Пример дерево -
563
---564
---565 (хочу удалить эту запись и всех ее потомков, которые соответствуют условиям)
--------566 (удалить)
------------568 (удалить)
-----------------576 (оставить)
------------571 (удалить)
--------567 (удалить)
--------569 (оставить)
--------577 (оставить)
--------578 (оставить)
-------------584 (оставить)
Неправильная идеология "оставить"...
Сначала надо перенести нужные "оставляемые" узлы в другие узлы, которые не удаляются. Ну а затем удалять 565, причем собрать всех его потомков через СТЕ. Простая задача...
1 июл 11, 15:31    [10907169]     Ответить | Цитировать Сообщить модератору
 Re: деревья - удаление  [new]
Tester666
Member

Откуда:
Сообщений: 179
Владимир СА
Сначала надо перенести нужные "оставляемые" узлы в другие узлы, которые не удаляются.

Вот в этом для меня и состоит загвоздка...как определить к какому родителю оставляемые узлы будут принадлежать?
4 июл 11, 07:08    [10916106]     Ответить | Цитировать Сообщить модератору
 Re: деревья - удаление  [new]
Владимир СА
Member

Откуда:
Сообщений: 7915
Tester666
Владимир СА
Сначала надо перенести нужные "оставляемые" узлы в другие узлы, которые не удаляются.

Вот в этом для меня и состоит загвоздка...как определить к какому родителю оставляемые узлы будут принадлежать?
У тебя наверное клиент-серверное приложение? Скорее всего так. Дык в нем пользователь и должен перенести оставляемые узлы в нужные для него узлы... Ну а потом уже производить удаление требуемого узла.
Надеюсь что ты создал такое приложение. Иначе зачем тебе дерево?
4 июл 11, 07:36    [10916117]     Ответить | Цитировать Сообщить модератору
 Re: деревья - удаление  [new]
Tester666
Member

Откуда:
Сообщений: 179
Условие задачи поменяли - решили оставлять узлы, если там есть хоть 1 неудаляемая ветка.
Вроде получилось реализовать, надо тестировать еще будет.
Всем спасибо за советы...
5 июл 11, 15:36    [10925722]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить